mirror of
https://github.com/tloncorp/landscape.git
synced 2024-11-23 17:24:10 +03:00
Merge pull request #163 from tloncorp/hm/renaming-prerelease
meta: renaming prerelease
This commit is contained in:
commit
b0e36cecb7
225
desk/app/settings.hoon
Normal file
225
desk/app/settings.hoon
Normal file
@ -0,0 +1,225 @@
|
||||
/- *settings
|
||||
/+ verb, dbug, default-agent, agentio
|
||||
|%
|
||||
+$ card card:agent:gall
|
||||
+$ versioned-state
|
||||
$% state-0
|
||||
state-1
|
||||
state-2
|
||||
==
|
||||
+$ state-0 [%0 settings=settings-0]
|
||||
+$ state-1 [%1 settings=settings-1]
|
||||
+$ state-2 [%2 =settings]
|
||||
--
|
||||
=| state-2
|
||||
=* state -
|
||||
::
|
||||
%- agent:dbug
|
||||
%+ verb |
|
||||
^- agent:gall
|
||||
=<
|
||||
|_ =bowl:gall
|
||||
+* this .
|
||||
do ~(. +> bowl)
|
||||
def ~(. (default-agent this %|) bowl)
|
||||
io ~(. agentio bowl)
|
||||
::
|
||||
++ on-init
|
||||
:: XX: deprecated; migration code
|
||||
^- (quip card _this)
|
||||
:_ this
|
||||
:~ :* %pass
|
||||
/migrate
|
||||
%agent
|
||||
[our dap]:bowl
|
||||
%poke
|
||||
noun+!>(%migrate)
|
||||
== ==
|
||||
::
|
||||
++ on-save !>(state)
|
||||
::
|
||||
++ on-load
|
||||
|= =old=vase
|
||||
^- (quip card _this)
|
||||
=/ old !<(versioned-state old-vase)
|
||||
|-
|
||||
?- -.old
|
||||
%0 $(old [%1 +.old])
|
||||
%1 $(old [%2 (~(put by *^settings) %landscape settings.old)])
|
||||
%2 `this(state old)
|
||||
==
|
||||
::
|
||||
++ on-poke
|
||||
|= [mar=mark vas=vase]
|
||||
^- (quip card _this)
|
||||
?> (team:title our.bowl src.bowl)
|
||||
=^ cards state
|
||||
?+ mar (on-poke:def mar vas)
|
||||
%settings-event
|
||||
=/ evt=event !<(event vas)
|
||||
?- -.evt
|
||||
%put-bucket (put-bucket:do [desk key bucket]:evt)
|
||||
%del-bucket (del-bucket:do [desk key]:evt)
|
||||
%put-entry (put-entry:do [desk buc key val]:evt)
|
||||
%del-entry (del-entry:do [desk buc key]:evt)
|
||||
==
|
||||
::
|
||||
:: XX: deprecated; migration code
|
||||
%noun
|
||||
?> ?=(%migrate !<(%migrate vas))
|
||||
=/ bas /(scot %p our.bowl)/settings-store/(scot %da now.bowl)
|
||||
:- ~
|
||||
?. .^(? %gu (weld bas /$))
|
||||
state
|
||||
=/ ful .^(data %gx (weld bas /all/noun))
|
||||
?+ -.ful (on-poke:def mar vas)
|
||||
%all state(settings +.ful)
|
||||
==
|
||||
==
|
||||
[cards this]
|
||||
::
|
||||
++ on-watch
|
||||
|= pax=path
|
||||
^- (quip card _this)
|
||||
?> (team:title our.bowl src.bowl)
|
||||
?+ pax (on-watch:def pax)
|
||||
[%all ~]
|
||||
[~ this]
|
||||
::
|
||||
[%desk @ ~]
|
||||
=* desk i.t.pax
|
||||
[~ this]
|
||||
::
|
||||
[%bucket @ @ ~]
|
||||
=* desk i.t.pax
|
||||
=* bucket-key i.t.t.pax
|
||||
?> (~(has bi settings) desk bucket-key)
|
||||
[~ this]
|
||||
::
|
||||
[%entry @ @ @ ~]
|
||||
=* desk i.t.pax
|
||||
=* bucket-key i.t.t.pax
|
||||
=* entry-key i.t.t.t.pax
|
||||
=/ bucket (~(got bi settings) desk bucket-key)
|
||||
?> (~(has by bucket) entry-key)
|
||||
[~ this]
|
||||
==
|
||||
::
|
||||
++ on-peek
|
||||
|= pax=path
|
||||
^- (unit (unit cage))
|
||||
?+ pax (on-peek:def pax)
|
||||
[%x %all ~]
|
||||
``settings-data+!>(`data`all+settings)
|
||||
::
|
||||
[%x %desk @ ~]
|
||||
=* desk i.t.t.pax
|
||||
=/ desk-settings (~(gut by settings) desk ~)
|
||||
``settings-data+!>(desk+desk-settings)
|
||||
::
|
||||
[%x %bucket @ @ ~]
|
||||
=* desk i.t.t.pax
|
||||
=* buc i.t.t.t.pax
|
||||
=/ bucket=(unit bucket) (~(get bi settings) desk buc)
|
||||
?~ bucket [~ ~]
|
||||
``settings-data+!>(`data`bucket+u.bucket)
|
||||
::
|
||||
[%x %entry @ @ @ ~]
|
||||
=* desk i.t.t.pax
|
||||
=* buc i.t.t.t.pax
|
||||
=* key i.t.t.t.t.pax
|
||||
=/ =bucket (~(gut bi settings) desk buc *bucket)
|
||||
=/ entry=(unit val) (~(get by bucket) key)
|
||||
?~ entry [~ ~]
|
||||
``settings-data+!>(`data`entry+u.entry)
|
||||
::
|
||||
[%x %has-bucket @ @ ~]
|
||||
=/ desk i.t.t.pax
|
||||
=/ buc i.t.t.t.pax
|
||||
=/ has-bucket=? (~(has bi settings) desk buc)
|
||||
``noun+!>(`?`has-bucket)
|
||||
::
|
||||
[%x %has-entry @ @ @ ~]
|
||||
=* desk i.t.t.pax
|
||||
=* buc i.t.t.t.pax
|
||||
=* key i.t.t.t.t.pax
|
||||
=/ =bucket (~(gut bi settings) desk buc *bucket)
|
||||
=/ has-entry=? (~(has by bucket) key)
|
||||
``noun+!>(`?`has-entry)
|
||||
==
|
||||
::
|
||||
++ on-agent on-agent:def
|
||||
++ on-leave on-leave:def
|
||||
++ on-arvo on-arvo:def
|
||||
++ on-fail on-fail:def
|
||||
--
|
||||
::
|
||||
|_ bol=bowl:gall
|
||||
::
|
||||
:: +put-bucket: put a bucket in the top level settings map, overwriting if it
|
||||
:: already exists
|
||||
::
|
||||
++ put-bucket
|
||||
|= [=desk =key =bucket]
|
||||
^- (quip card _state)
|
||||
=/ pas=(list path)
|
||||
:~ /all
|
||||
/desk/[desk]
|
||||
/bucket/[desk]/[key]
|
||||
==
|
||||
:- [(give-event pas %put-bucket desk key bucket)]~
|
||||
state(settings (~(put bi settings) desk key bucket))
|
||||
::
|
||||
:: +del-bucket: delete a bucket from the top level settings map
|
||||
::
|
||||
++ del-bucket
|
||||
|= [=desk =key]
|
||||
^- (quip card _state)
|
||||
=/ pas=(list path)
|
||||
:~ /all
|
||||
/desk/[desk]
|
||||
/bucket/[key]
|
||||
==
|
||||
:- [(give-event pas %del-bucket desk key)]~
|
||||
state(settings (~(del bi settings) desk key))
|
||||
::
|
||||
:: +put-entry: put an entry in a bucket, overwriting if it already exists
|
||||
:: if bucket does not yet exist, create it
|
||||
::
|
||||
++ put-entry
|
||||
|= [=desk buc=key =key =val]
|
||||
^- (quip card _state)
|
||||
=/ pas=(list path)
|
||||
:~ /all
|
||||
/desk/[desk]
|
||||
/bucket/[desk]/[buc]
|
||||
/entry/[desk]/[buc]/[key]
|
||||
==
|
||||
=/ =bucket (~(put by (~(gut bi settings) desk buc *bucket)) key val)
|
||||
:- [(give-event pas %put-entry desk buc key val)]~
|
||||
state(settings (~(put bi settings) desk buc bucket))
|
||||
::
|
||||
:: +del-entry: delete an entry from a bucket, fail quietly if bucket does not
|
||||
:: exist
|
||||
::
|
||||
++ del-entry
|
||||
|= [=desk buc=key =key]
|
||||
^- (quip card _state)
|
||||
=/ pas=(list path)
|
||||
:~ /all
|
||||
/desk/[desk]
|
||||
/bucket/[desk]/[buc]
|
||||
/entry/[desk]/[buc]/[key]
|
||||
==
|
||||
=/ bucket=(unit bucket) (~(get bi settings) desk buc)
|
||||
?~ bucket
|
||||
[~ state]
|
||||
=. u.bucket (~(del by u.bucket) key)
|
||||
:- [(give-event pas %del-entry desk buc key)]~
|
||||
state(settings (~(put bi settings) desk buc u.bucket))
|
||||
::
|
||||
++ give-event
|
||||
|= [pas=(list path) evt=event]
|
||||
^- card
|
||||
[%give %fact pas %settings-event !>(evt)]
|
||||
--
|
168
desk/app/storage.hoon
Normal file
168
desk/app/storage.hoon
Normal file
@ -0,0 +1,168 @@
|
||||
:: storage:
|
||||
::
|
||||
:: stores s3 keys for uploading and sharing images and objects
|
||||
::
|
||||
/- *storage
|
||||
/+ storage-json, default-agent, verb, dbug
|
||||
~% %s3-top ..part ~
|
||||
|%
|
||||
+$ card card:agent:gall
|
||||
+$ versioned-state
|
||||
$% state-zero
|
||||
state-one
|
||||
==
|
||||
::
|
||||
+$ state-zero [%0 =credentials:zero:past =configuration:zero:past]
|
||||
+$ state-one [%1 =credentials =configuration]
|
||||
--
|
||||
::
|
||||
=| state-one
|
||||
=* state -
|
||||
::
|
||||
%- agent:dbug
|
||||
%+ verb |
|
||||
^- agent:gall
|
||||
~% %s3-agent-core ..card ~
|
||||
|_ =bowl:gall
|
||||
+* this .
|
||||
def ~(. (default-agent this %|) bowl)
|
||||
::
|
||||
++ on-init
|
||||
:: XX: deprecated; migration code
|
||||
^- (quip card _this)
|
||||
:_ this
|
||||
:~ :* %pass
|
||||
/migrate
|
||||
%agent
|
||||
[our dap]:bowl
|
||||
%poke
|
||||
noun+!>(%migrate)
|
||||
== ==
|
||||
++ on-save !>(state)
|
||||
++ on-load
|
||||
|= =vase
|
||||
=/ old !<(versioned-state vase)
|
||||
|^
|
||||
?- -.old
|
||||
%1 `this(state old)
|
||||
%0 `this(state (state-0-to-1 old))
|
||||
==
|
||||
++ state-0-to-1
|
||||
|= zer=state-zero
|
||||
^- state-one
|
||||
:* %1
|
||||
credentials.zer
|
||||
(configuration-0-to-1 configuration.zer)
|
||||
==
|
||||
++ configuration-0-to-1
|
||||
|= conf=configuration:zero:past
|
||||
^- ^configuration
|
||||
:* buckets.conf
|
||||
current-bucket.conf
|
||||
''
|
||||
==
|
||||
--
|
||||
::
|
||||
++ on-poke
|
||||
~/ %s3-poke
|
||||
|= [=mark =vase]
|
||||
^- (quip card _this)
|
||||
|^
|
||||
?> (team:title our.bowl src.bowl)
|
||||
=^ cards state
|
||||
?+ mark (on-poke:def mark vase)
|
||||
%storage-action
|
||||
(poke-action !<(action vase))
|
||||
::
|
||||
:: XX: deprecated; migration code
|
||||
%noun
|
||||
?> ?=(%migrate !<(%migrate vase))
|
||||
=/ bas /(scot %p our.bowl)/s3-store/(scot %da now.bowl)
|
||||
:- ~
|
||||
?. .^(? %gu (weld bas /$))
|
||||
state
|
||||
=:
|
||||
credentials
|
||||
=/ ful .^(update %gx (weld bas /credentials/noun))
|
||||
?+ -.ful (on-poke:def mark vase)
|
||||
%credentials +.ful
|
||||
==
|
||||
::
|
||||
configuration
|
||||
=/ ful .^(update %gx (weld bas /configuration/noun))
|
||||
?+ -.ful (on-poke:def mark vase)
|
||||
%configuration +.ful
|
||||
== ==
|
||||
state
|
||||
==
|
||||
[cards this]
|
||||
::
|
||||
++ poke-action
|
||||
|= act=action
|
||||
^- (quip card _state)
|
||||
:- [%give %fact [/all]~ %storage-update !>(act)]~
|
||||
?- -.act
|
||||
%set-endpoint
|
||||
state(endpoint.credentials endpoint.act)
|
||||
::
|
||||
%set-access-key-id
|
||||
state(access-key-id.credentials access-key-id.act)
|
||||
::
|
||||
%set-secret-access-key
|
||||
state(secret-access-key.credentials secret-access-key.act)
|
||||
::
|
||||
%set-region
|
||||
state(region.configuration region.act)
|
||||
::
|
||||
%set-current-bucket
|
||||
%_ state
|
||||
current-bucket.configuration bucket.act
|
||||
buckets.configuration (~(put in buckets.configuration) bucket.act)
|
||||
==
|
||||
::
|
||||
%add-bucket
|
||||
state(buckets.configuration (~(put in buckets.configuration) bucket.act))
|
||||
::
|
||||
%remove-bucket
|
||||
state(buckets.configuration (~(del in buckets.configuration) bucket.act))
|
||||
==
|
||||
--
|
||||
::
|
||||
++ on-watch
|
||||
~/ %s3-watch
|
||||
|= =path
|
||||
^- (quip card _this)
|
||||
|^
|
||||
?> (team:title our.bowl src.bowl)
|
||||
=/ cards=(list card)
|
||||
?+ path (on-watch:def path)
|
||||
[%all ~]
|
||||
:~ (give %storage-update !>([%credentials credentials]))
|
||||
(give %storage-update !>([%configuration configuration]))
|
||||
==
|
||||
==
|
||||
[cards this]
|
||||
::
|
||||
++ give
|
||||
|= =cage
|
||||
^- card
|
||||
[%give %fact ~ cage]
|
||||
--
|
||||
::
|
||||
++ on-leave on-leave:def
|
||||
++ on-peek
|
||||
~/ %s3-peek
|
||||
|= =path
|
||||
^- (unit (unit cage))
|
||||
?. (team:title our.bowl src.bowl) ~
|
||||
?+ path [~ ~]
|
||||
[%x %credentials ~]
|
||||
[~ ~ %storage-update !>(`update`[%credentials credentials])]
|
||||
::
|
||||
[%x %configuration ~]
|
||||
[~ ~ %storage-update !>(`update`[%configuration configuration])]
|
||||
==
|
||||
++ on-agent on-agent:def
|
||||
++ on-arvo on-arvo:def
|
||||
++ on-fail on-fail:def
|
||||
--
|
@ -2,7 +2,9 @@
|
||||
%treaty
|
||||
%hark-store
|
||||
%hark-system-hook
|
||||
%settings
|
||||
%settings-store
|
||||
%storage
|
||||
%reel
|
||||
%bait
|
||||
==
|
||||
|
53
desk/lib/storage-json.hoon
Normal file
53
desk/lib/storage-json.hoon
Normal file
@ -0,0 +1,53 @@
|
||||
/- *storage
|
||||
|%
|
||||
++ json-to-action
|
||||
|= =json
|
||||
^- action
|
||||
=, format
|
||||
|^ (parse-json json)
|
||||
++ parse-json
|
||||
%- of:dejs
|
||||
:~ [%set-endpoint so:dejs]
|
||||
[%set-access-key-id so:dejs]
|
||||
[%set-secret-access-key so:dejs]
|
||||
[%set-region so:dejs]
|
||||
[%add-bucket so:dejs]
|
||||
[%remove-bucket so:dejs]
|
||||
[%set-current-bucket so:dejs]
|
||||
==
|
||||
--
|
||||
::
|
||||
++ update-to-json
|
||||
|= upd=update
|
||||
^- json
|
||||
=, format
|
||||
%+ frond:enjs %s3-update
|
||||
%- pairs:enjs
|
||||
:~ ?- -.upd
|
||||
%set-current-bucket [%'setCurrentBucket' s+bucket.upd]
|
||||
%add-bucket [%'addBucket' s+bucket.upd]
|
||||
%set-region [%'setRegion' s+region.upd]
|
||||
%remove-bucket [%'removeBucket' s+bucket.upd]
|
||||
%set-endpoint [%'setEndpoint' s+endpoint.upd]
|
||||
%set-access-key-id [%'setAccessKeyId' s+access-key-id.upd]
|
||||
%set-secret-access-key
|
||||
[%'setSecretAccessKey' s+secret-access-key.upd]
|
||||
::
|
||||
%credentials
|
||||
:- %credentials
|
||||
%- pairs:enjs
|
||||
:~ [%endpoint s+endpoint.credentials.upd]
|
||||
[%'accessKeyId' s+access-key-id.credentials.upd]
|
||||
[%'secretAccessKey' s+secret-access-key.credentials.upd]
|
||||
==
|
||||
::
|
||||
%configuration
|
||||
:- %configuration
|
||||
%- pairs:enjs
|
||||
:~ [%buckets a+(turn ~(tap in buckets.configuration.upd) |=(a=@t s+a))]
|
||||
[%'currentBucket' s+current-bucket.configuration.upd]
|
||||
[%'region' s+region.configuration.upd]
|
||||
==
|
||||
==
|
||||
==
|
||||
--
|
13
desk/mar/storage/action.hoon
Normal file
13
desk/mar/storage/action.hoon
Normal file
@ -0,0 +1,13 @@
|
||||
/+ *storage-json
|
||||
|_ act=action
|
||||
++ grad %noun
|
||||
++ grow
|
||||
|%
|
||||
++ noun act
|
||||
--
|
||||
++ grab
|
||||
|%
|
||||
++ noun action
|
||||
++ json json-to-action
|
||||
--
|
||||
--
|
14
desk/mar/storage/update.hoon
Normal file
14
desk/mar/storage/update.hoon
Normal file
@ -0,0 +1,14 @@
|
||||
/+ *storage-json
|
||||
|_ upd=update
|
||||
++ grad %noun
|
||||
++ grow
|
||||
|%
|
||||
++ noun upd
|
||||
++ json (update-to-json upd)
|
||||
--
|
||||
::
|
||||
++ grab
|
||||
|%
|
||||
++ noun update
|
||||
--
|
||||
--
|
27
desk/sur/storage-0.hoon
Normal file
27
desk/sur/storage-0.hoon
Normal file
@ -0,0 +1,27 @@
|
||||
|%
|
||||
+$ credentials
|
||||
$: endpoint=@t
|
||||
access-key-id=@t
|
||||
secret-access-key=@t
|
||||
==
|
||||
::
|
||||
+$ configuration
|
||||
$: buckets=(set @t)
|
||||
current-bucket=@t
|
||||
==
|
||||
::
|
||||
+$ action
|
||||
$% [%set-endpoint endpoint=@t]
|
||||
[%set-access-key-id access-key-id=@t]
|
||||
[%set-secret-access-key secret-access-key=@t]
|
||||
[%add-bucket bucket=@t]
|
||||
[%remove-bucket bucket=@t]
|
||||
[%set-current-bucket bucket=@t]
|
||||
==
|
||||
::
|
||||
+$ update
|
||||
$% [%credentials =credentials]
|
||||
[%configuration =configuration]
|
||||
action
|
||||
==
|
||||
--
|
34
desk/sur/storage.hoon
Normal file
34
desk/sur/storage.hoon
Normal file
@ -0,0 +1,34 @@
|
||||
/- zer=storage-0
|
||||
|%
|
||||
++ past
|
||||
|%
|
||||
++ zero zer
|
||||
--
|
||||
+$ credentials
|
||||
$: endpoint=@t
|
||||
access-key-id=@t
|
||||
secret-access-key=@t
|
||||
==
|
||||
::
|
||||
+$ configuration
|
||||
$: buckets=(set @t)
|
||||
current-bucket=@t
|
||||
region=@t
|
||||
==
|
||||
::
|
||||
+$ action
|
||||
$% [%set-endpoint endpoint=@t]
|
||||
[%set-access-key-id access-key-id=@t]
|
||||
[%set-secret-access-key secret-access-key=@t]
|
||||
[%add-bucket bucket=@t]
|
||||
[%remove-bucket bucket=@t]
|
||||
[%set-current-bucket bucket=@t]
|
||||
[%set-region region=@t]
|
||||
==
|
||||
::
|
||||
+$ update
|
||||
$% [%credentials =credentials]
|
||||
[%configuration =configuration]
|
||||
action
|
||||
==
|
||||
--
|
@ -2,6 +2,9 @@
|
||||
"name": "landscape",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": "^16.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"mock": "vite --mode mock",
|
||||
|
@ -2,21 +2,22 @@
|
||||
/* tslint:disable */
|
||||
|
||||
/**
|
||||
* Mock Service Worker (1.2.1).
|
||||
* Mock Service Worker (0.39.2).
|
||||
* @see https://github.com/mswjs/msw
|
||||
* - Please do NOT modify this file.
|
||||
* - Please do NOT serve this file on production.
|
||||
*/
|
||||
|
||||
const INTEGRITY_CHECKSUM = '3d6b9f06410d179a7f7404d4bf4c3c70'
|
||||
const INTEGRITY_CHECKSUM = '02f4ad4a2797f85668baf196e553d929'
|
||||
const bypassHeaderName = 'x-msw-bypass'
|
||||
const activeClientIds = new Set()
|
||||
|
||||
self.addEventListener('install', function () {
|
||||
self.skipWaiting()
|
||||
return self.skipWaiting()
|
||||
})
|
||||
|
||||
self.addEventListener('activate', function (event) {
|
||||
event.waitUntil(self.clients.claim())
|
||||
self.addEventListener('activate', async function (event) {
|
||||
return self.clients.claim()
|
||||
})
|
||||
|
||||
self.addEventListener('message', async function (event) {
|
||||
@ -32,9 +33,7 @@ self.addEventListener('message', async function (event) {
|
||||
return
|
||||
}
|
||||
|
||||
const allClients = await self.clients.matchAll({
|
||||
type: 'window',
|
||||
})
|
||||
const allClients = await self.clients.matchAll()
|
||||
|
||||
switch (event.data) {
|
||||
case 'KEEPALIVE_REQUEST': {
|
||||
@ -84,6 +83,161 @@ self.addEventListener('message', async function (event) {
|
||||
}
|
||||
})
|
||||
|
||||
// Resolve the "main" client for the given event.
|
||||
// Client that issues a request doesn't necessarily equal the client
|
||||
// that registered the worker. It's with the latter the worker should
|
||||
// communicate with during the response resolving phase.
|
||||
async function resolveMainClient(event) {
|
||||
const client = await self.clients.get(event.clientId)
|
||||
|
||||
if (client.frameType === 'top-level') {
|
||||
return client
|
||||
}
|
||||
|
||||
const allClients = await self.clients.matchAll()
|
||||
|
||||
return allClients
|
||||
.filter((client) => {
|
||||
// Get only those clients that are currently visible.
|
||||
return client.visibilityState === 'visible'
|
||||
})
|
||||
.find((client) => {
|
||||
// Find the client ID that's recorded in the
|
||||
// set of clients that have registered the worker.
|
||||
return activeClientIds.has(client.id)
|
||||
})
|
||||
}
|
||||
|
||||
async function handleRequest(event, requestId) {
|
||||
const client = await resolveMainClient(event)
|
||||
const response = await getResponse(event, client, requestId)
|
||||
|
||||
// Send back the response clone for the "response:*" life-cycle events.
|
||||
// Ensure MSW is active and ready to handle the message, otherwise
|
||||
// this message will pend indefinitely.
|
||||
if (client && activeClientIds.has(client.id)) {
|
||||
;(async function () {
|
||||
const clonedResponse = response.clone()
|
||||
sendToClient(client, {
|
||||
type: 'RESPONSE',
|
||||
payload: {
|
||||
requestId,
|
||||
type: clonedResponse.type,
|
||||
ok: clonedResponse.ok,
|
||||
status: clonedResponse.status,
|
||||
statusText: clonedResponse.statusText,
|
||||
body:
|
||||
clonedResponse.body === null ? null : await clonedResponse.text(),
|
||||
headers: serializeHeaders(clonedResponse.headers),
|
||||
redirected: clonedResponse.redirected,
|
||||
},
|
||||
})
|
||||
})()
|
||||
}
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
async function getResponse(event, client, requestId) {
|
||||
const { request } = event
|
||||
const requestClone = request.clone()
|
||||
const getOriginalResponse = () => fetch(requestClone)
|
||||
|
||||
// Bypass mocking when the request client is not active.
|
||||
if (!client) {
|
||||
return getOriginalResponse()
|
||||
}
|
||||
|
||||
// Bypass initial page load requests (i.e. static assets).
|
||||
// The absence of the immediate/parent client in the map of the active clients
|
||||
// means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet
|
||||
// and is not ready to handle requests.
|
||||
if (!activeClientIds.has(client.id)) {
|
||||
return await getOriginalResponse()
|
||||
}
|
||||
|
||||
// Bypass requests with the explicit bypass header
|
||||
if (requestClone.headers.get(bypassHeaderName) === 'true') {
|
||||
const cleanRequestHeaders = serializeHeaders(requestClone.headers)
|
||||
|
||||
// Remove the bypass header to comply with the CORS preflight check.
|
||||
delete cleanRequestHeaders[bypassHeaderName]
|
||||
|
||||
const originalRequest = new Request(requestClone, {
|
||||
headers: new Headers(cleanRequestHeaders),
|
||||
})
|
||||
|
||||
return fetch(originalRequest)
|
||||
}
|
||||
|
||||
// Send the request to the client-side MSW.
|
||||
const reqHeaders = serializeHeaders(request.headers)
|
||||
const body = await request.text()
|
||||
|
||||
const clientMessage = await sendToClient(client, {
|
||||
type: 'REQUEST',
|
||||
payload: {
|
||||
id: requestId,
|
||||
url: request.url,
|
||||
method: request.method,
|
||||
headers: reqHeaders,
|
||||
cache: request.cache,
|
||||
mode: request.mode,
|
||||
credentials: request.credentials,
|
||||
destination: request.destination,
|
||||
integrity: request.integrity,
|
||||
redirect: request.redirect,
|
||||
referrer: request.referrer,
|
||||
referrerPolicy: request.referrerPolicy,
|
||||
body,
|
||||
bodyUsed: request.bodyUsed,
|
||||
keepalive: request.keepalive,
|
||||
},
|
||||
})
|
||||
|
||||
switch (clientMessage.type) {
|
||||
case 'MOCK_SUCCESS': {
|
||||
return delayPromise(
|
||||
() => respondWithMock(clientMessage),
|
||||
clientMessage.payload.delay,
|
||||
)
|
||||
}
|
||||
|
||||
case 'MOCK_NOT_FOUND': {
|
||||
return getOriginalResponse()
|
||||
}
|
||||
|
||||
case 'NETWORK_ERROR': {
|
||||
const { name, message } = clientMessage.payload
|
||||
const networkError = new Error(message)
|
||||
networkError.name = name
|
||||
|
||||
// Rejecting a request Promise emulates a network error.
|
||||
throw networkError
|
||||
}
|
||||
|
||||
case 'INTERNAL_ERROR': {
|
||||
const parsedBody = JSON.parse(clientMessage.payload.body)
|
||||
|
||||
console.error(
|
||||
`\
|
||||
[MSW] Uncaught exception in the request handler for "%s %s":
|
||||
|
||||
${parsedBody.location}
|
||||
|
||||
This exception has been gracefully handled as a 500 response, however, it's strongly recommended to resolve this error, as it indicates a mistake in your code. If you wish to mock an error response, please see this guide: https://mswjs.io/docs/recipes/mocking-error-responses\
|
||||
`,
|
||||
request.method,
|
||||
request.url,
|
||||
)
|
||||
|
||||
return respondWithMock(clientMessage)
|
||||
}
|
||||
}
|
||||
|
||||
return getOriginalResponse()
|
||||
}
|
||||
|
||||
self.addEventListener('fetch', function (event) {
|
||||
const { request } = event
|
||||
const accept = request.headers.get('accept') || ''
|
||||
@ -111,10 +265,9 @@ self.addEventListener('fetch', function (event) {
|
||||
return
|
||||
}
|
||||
|
||||
// Generate unique request ID.
|
||||
const requestId = Math.random().toString(16).slice(2)
|
||||
const requestId = uuidv4()
|
||||
|
||||
event.respondWith(
|
||||
return event.respondWith(
|
||||
handleRequest(event, requestId).catch((error) => {
|
||||
if (error.name === 'NetworkError') {
|
||||
console.warn(
|
||||
@ -137,142 +290,14 @@ self.addEventListener('fetch', function (event) {
|
||||
)
|
||||
})
|
||||
|
||||
async function handleRequest(event, requestId) {
|
||||
const client = await resolveMainClient(event)
|
||||
const response = await getResponse(event, client, requestId)
|
||||
|
||||
// Send back the response clone for the "response:*" life-cycle events.
|
||||
// Ensure MSW is active and ready to handle the message, otherwise
|
||||
// this message will pend indefinitely.
|
||||
if (client && activeClientIds.has(client.id)) {
|
||||
;(async function () {
|
||||
const clonedResponse = response.clone()
|
||||
sendToClient(client, {
|
||||
type: 'RESPONSE',
|
||||
payload: {
|
||||
requestId,
|
||||
type: clonedResponse.type,
|
||||
ok: clonedResponse.ok,
|
||||
status: clonedResponse.status,
|
||||
statusText: clonedResponse.statusText,
|
||||
body:
|
||||
clonedResponse.body === null ? null : await clonedResponse.text(),
|
||||
headers: Object.fromEntries(clonedResponse.headers.entries()),
|
||||
redirected: clonedResponse.redirected,
|
||||
},
|
||||
})
|
||||
})()
|
||||
}
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
// Resolve the main client for the given event.
|
||||
// Client that issues a request doesn't necessarily equal the client
|
||||
// that registered the worker. It's with the latter the worker should
|
||||
// communicate with during the response resolving phase.
|
||||
async function resolveMainClient(event) {
|
||||
const client = await self.clients.get(event.clientId)
|
||||
|
||||
if (client?.frameType === 'top-level') {
|
||||
return client
|
||||
}
|
||||
|
||||
const allClients = await self.clients.matchAll({
|
||||
type: 'window',
|
||||
function serializeHeaders(headers) {
|
||||
const reqHeaders = {}
|
||||
headers.forEach((value, name) => {
|
||||
reqHeaders[name] = reqHeaders[name]
|
||||
? [].concat(reqHeaders[name]).concat(value)
|
||||
: value
|
||||
})
|
||||
|
||||
return allClients
|
||||
.filter((client) => {
|
||||
// Get only those clients that are currently visible.
|
||||
return client.visibilityState === 'visible'
|
||||
})
|
||||
.find((client) => {
|
||||
// Find the client ID that's recorded in the
|
||||
// set of clients that have registered the worker.
|
||||
return activeClientIds.has(client.id)
|
||||
})
|
||||
}
|
||||
|
||||
async function getResponse(event, client, requestId) {
|
||||
const { request } = event
|
||||
const clonedRequest = request.clone()
|
||||
|
||||
function passthrough() {
|
||||
// Clone the request because it might've been already used
|
||||
// (i.e. its body has been read and sent to the client).
|
||||
const headers = Object.fromEntries(clonedRequest.headers.entries())
|
||||
|
||||
// Remove MSW-specific request headers so the bypassed requests
|
||||
// comply with the server's CORS preflight check.
|
||||
// Operate with the headers as an object because request "Headers"
|
||||
// are immutable.
|
||||
delete headers['x-msw-bypass']
|
||||
|
||||
return fetch(clonedRequest, { headers })
|
||||
}
|
||||
|
||||
// Bypass mocking when the client is not active.
|
||||
if (!client) {
|
||||
return passthrough()
|
||||
}
|
||||
|
||||
// Bypass initial page load requests (i.e. static assets).
|
||||
// The absence of the immediate/parent client in the map of the active clients
|
||||
// means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet
|
||||
// and is not ready to handle requests.
|
||||
if (!activeClientIds.has(client.id)) {
|
||||
return passthrough()
|
||||
}
|
||||
|
||||
// Bypass requests with the explicit bypass header.
|
||||
// Such requests can be issued by "ctx.fetch()".
|
||||
if (request.headers.get('x-msw-bypass') === 'true') {
|
||||
return passthrough()
|
||||
}
|
||||
|
||||
// Notify the client that a request has been intercepted.
|
||||
const clientMessage = await sendToClient(client, {
|
||||
type: 'REQUEST',
|
||||
payload: {
|
||||
id: requestId,
|
||||
url: request.url,
|
||||
method: request.method,
|
||||
headers: Object.fromEntries(request.headers.entries()),
|
||||
cache: request.cache,
|
||||
mode: request.mode,
|
||||
credentials: request.credentials,
|
||||
destination: request.destination,
|
||||
integrity: request.integrity,
|
||||
redirect: request.redirect,
|
||||
referrer: request.referrer,
|
||||
referrerPolicy: request.referrerPolicy,
|
||||
body: await request.text(),
|
||||
bodyUsed: request.bodyUsed,
|
||||
keepalive: request.keepalive,
|
||||
},
|
||||
})
|
||||
|
||||
switch (clientMessage.type) {
|
||||
case 'MOCK_RESPONSE': {
|
||||
return respondWithMock(clientMessage.data)
|
||||
}
|
||||
|
||||
case 'MOCK_NOT_FOUND': {
|
||||
return passthrough()
|
||||
}
|
||||
|
||||
case 'NETWORK_ERROR': {
|
||||
const { name, message } = clientMessage.data
|
||||
const networkError = new Error(message)
|
||||
networkError.name = name
|
||||
|
||||
// Rejecting a "respondWith" promise emulates a network error.
|
||||
throw networkError
|
||||
}
|
||||
}
|
||||
|
||||
return passthrough()
|
||||
return reqHeaders
|
||||
}
|
||||
|
||||
function sendToClient(client, message) {
|
||||
@ -287,17 +312,27 @@ function sendToClient(client, message) {
|
||||
resolve(event.data)
|
||||
}
|
||||
|
||||
client.postMessage(message, [channel.port2])
|
||||
client.postMessage(JSON.stringify(message), [channel.port2])
|
||||
})
|
||||
}
|
||||
|
||||
function sleep(timeMs) {
|
||||
function delayPromise(cb, duration) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(resolve, timeMs)
|
||||
setTimeout(() => resolve(cb()), duration)
|
||||
})
|
||||
}
|
||||
|
||||
async function respondWithMock(response) {
|
||||
await sleep(response.delay)
|
||||
return new Response(response.body, response)
|
||||
function respondWithMock(clientMessage) {
|
||||
return new Response(clientMessage.payload.body, {
|
||||
...clientMessage.payload,
|
||||
headers: clientMessage.payload.headers,
|
||||
})
|
||||
}
|
||||
|
||||
function uuidv4() {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
||||
const r = (Math.random() * 16) | 0
|
||||
const v = c == 'x' ? r : (r & 0x3) | 0x8
|
||||
return v.toString(16)
|
||||
})
|
||||
}
|
||||
|
@ -1,11 +1,5 @@
|
||||
import React, { useCallback, useState, FormEvent, useEffect } from 'react';
|
||||
import api from '../state/api';
|
||||
import {
|
||||
setAccessKeyId,
|
||||
setCurrentBucket,
|
||||
setEndpoint,
|
||||
setSecretAccessKey,
|
||||
} from '@urbit/api';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import cn from 'classnames';
|
||||
import { useAsyncCall } from '../logic/useAsyncCall';
|
||||
@ -21,6 +15,23 @@ interface CredentialsSubmit {
|
||||
bucket: string;
|
||||
}
|
||||
|
||||
type S3Update =
|
||||
| { 'set-region': string }
|
||||
| { 'set-endpoint': string }
|
||||
| { 'set-access-key-id': string }
|
||||
| { 'set-secret-access-key': string }
|
||||
| { 'set-current-bucket': string }
|
||||
| { 'add-bucket': string }
|
||||
| { 'remove-bucket': string };
|
||||
|
||||
function storagePoke(data: S3Update | { 'set-region': string }) {
|
||||
return {
|
||||
app: 'storage',
|
||||
mark: 'storage-action',
|
||||
json: data,
|
||||
};
|
||||
}
|
||||
|
||||
export const StoragePrefs = () => {
|
||||
const { s3, loaded, ...storageState } = useStorageState();
|
||||
|
||||
@ -35,15 +46,11 @@ export const StoragePrefs = () => {
|
||||
|
||||
const { call: addS3Credentials, status } = useAsyncCall(
|
||||
useCallback(async (data: CredentialsSubmit) => {
|
||||
api.poke(setEndpoint(data.endpoint));
|
||||
api.poke(setAccessKeyId(data.accessId));
|
||||
api.poke(setSecretAccessKey(data.accessSecret));
|
||||
api.poke(setCurrentBucket(data.bucket));
|
||||
api.poke({
|
||||
app: 's3-store',
|
||||
mark: 's3-action',
|
||||
json: { 'set-region': data.region },
|
||||
});
|
||||
api.poke(storagePoke({ 'set-endpoint': data.endpoint }));
|
||||
api.poke(storagePoke({ 'set-access-key-id': data.accessId }));
|
||||
api.poke(storagePoke({ 'set-secret-access-key': data.accessSecret }));
|
||||
api.poke(storagePoke({ 'set-current-bucket': data.bucket }));
|
||||
api.poke(storagePoke({ 'set-region': data.region }));
|
||||
}, [])
|
||||
);
|
||||
|
||||
|
@ -1,11 +1,5 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import {
|
||||
SettingsUpdate,
|
||||
Value,
|
||||
putEntry as doPutEntry,
|
||||
getDeskSettings,
|
||||
DeskData,
|
||||
} from '@urbit/api';
|
||||
import { SettingsUpdate, Value, DeskData } from '@urbit/api';
|
||||
import _ from 'lodash';
|
||||
import {
|
||||
BaseState,
|
||||
@ -109,12 +103,27 @@ export const useSettingsState = createState<BaseSettingsState>(
|
||||
},
|
||||
loaded: false,
|
||||
putEntry: async (bucket, key, val) => {
|
||||
const poke = doPutEntry(window.desk, bucket, key, val);
|
||||
const poke = {
|
||||
app: 'settings',
|
||||
mark: 'settings-update',
|
||||
json: {
|
||||
'put-entry': {
|
||||
desk: window.desk,
|
||||
'bucket-key': bucket,
|
||||
'entry-key': key,
|
||||
value: val,
|
||||
},
|
||||
},
|
||||
};
|
||||
await pokeOptimisticallyN(useSettingsState, poke, reduceUpdate);
|
||||
},
|
||||
fetchAll: async () => {
|
||||
const result = (await api.scry<DeskData>(getDeskSettings(window.desk)))
|
||||
.desk;
|
||||
const result = (
|
||||
await api.scry<DeskData>({
|
||||
app: 'settings',
|
||||
path: `/desk/${window.desk}`,
|
||||
})
|
||||
).desk;
|
||||
const newState = {
|
||||
..._.mergeWith(get(), result, (obj, src) =>
|
||||
_.isArray(src) ? src : undefined
|
||||
@ -127,7 +136,7 @@ export const useSettingsState = createState<BaseSettingsState>(
|
||||
[],
|
||||
[
|
||||
(set, get) =>
|
||||
createSubscription('settings-store', `/desk/${window.desk}`, (e) => {
|
||||
createSubscription('settings', `/desk/${window.desk}`, (e) => {
|
||||
const data = _.get(e, 'settings-event', false);
|
||||
if (data) {
|
||||
reduceStateN(get(), data, reduceUpdate);
|
||||
|
@ -35,7 +35,7 @@ export interface BaseStorageState {
|
||||
[ref: string]: unknown;
|
||||
}
|
||||
|
||||
export type StorageState = BaseStorageState & BaseState<BaseStorageState>
|
||||
export type StorageState = BaseStorageState & BaseState<BaseStorageState>;
|
||||
|
||||
export const useStorageState = createState<BaseStorageState>(
|
||||
'Storage',
|
||||
@ -48,7 +48,7 @@ export const useStorageState = createState<BaseStorageState>(
|
||||
inputMark: 'noun',
|
||||
outputMark: 'json',
|
||||
threadName: 'gcp-is-configured',
|
||||
body: {}
|
||||
body: {},
|
||||
});
|
||||
},
|
||||
getToken: async () => {
|
||||
@ -56,33 +56,33 @@ export const useStorageState = createState<BaseStorageState>(
|
||||
inputMark: 'noun',
|
||||
outputMark: 'gcp-token',
|
||||
threadName: 'gcp-get-token',
|
||||
body: {}
|
||||
body: {},
|
||||
});
|
||||
get().set((state) => {
|
||||
state.gcp.token = token;
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
s3: {
|
||||
configuration: {
|
||||
buckets: new Set(),
|
||||
currentBucket: '',
|
||||
region: 'global'
|
||||
region: 'global',
|
||||
},
|
||||
credentials: null
|
||||
}
|
||||
credentials: null,
|
||||
},
|
||||
}),
|
||||
['loaded', 's3', 'gcp'],
|
||||
[
|
||||
(set, get) =>
|
||||
createSubscription('s3-store', '/all', (e) => {
|
||||
createSubscription('storage', '/all', (e) => {
|
||||
const d = _.get(e, 's3-update', false);
|
||||
if (d) {
|
||||
console.log(d)
|
||||
console.log(d);
|
||||
reduceStateN(get(), d, reduce);
|
||||
set({ loaded: true });
|
||||
}
|
||||
})
|
||||
}),
|
||||
]
|
||||
);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user