pyric-admin 0.1.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +216 -0
- package/README.md +180 -0
- package/README.md.orig +48 -0
- package/dist/app/index.d.ts +47 -0
- package/dist/app/index.d.ts.map +1 -0
- package/dist/app/index.js +164 -0
- package/dist/app/index.js.map +1 -0
- package/dist/app/lifecycle.d.ts +7 -0
- package/dist/app/lifecycle.d.ts.map +1 -0
- package/dist/app/lifecycle.js +15 -0
- package/dist/app/lifecycle.js.map +1 -0
- package/dist/auth/index.d.ts +117 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +726 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/database/index.d.ts +152 -0
- package/dist/database/index.d.ts.map +1 -0
- package/dist/database/index.js +947 -0
- package/dist/database/index.js.map +1 -0
- package/dist/firestore/index.d.ts +32 -0
- package/dist/firestore/index.d.ts.map +1 -0
- package/dist/firestore/index.js +56 -0
- package/dist/firestore/index.js.map +1 -0
- package/dist/messaging/index.d.ts +154 -0
- package/dist/messaging/index.d.ts.map +1 -0
- package/dist/messaging/index.js +238 -0
- package/dist/messaging/index.js.map +1 -0
- package/dist/storage/index.d.ts +159 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +413 -0
- package/dist/storage/index.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `pyric-admin/storage` — sandbox mirror for the Admin Storage shape.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the useful `firebase-admin/storage` shape for local and remote
|
|
5
|
+
* sandbox apps selected at {@link initializeApp} time. Dispatch reads the
|
|
6
|
+
* {@link ADMIN_APP_TARGET} brand on the `PyricAdminApp` handle.
|
|
7
|
+
*
|
|
8
|
+
* - **Remote sandbox path** — a handle branded by `@pyric/cli`'
|
|
9
|
+
* `connectRemoteSandbox()`/`remoteSandbox()` relays every data
|
|
10
|
+
* operation over the bridge to the browser-hosted SharedWorker's
|
|
11
|
+
* object store (admin lens pinned — rules bypass). Single bucket;
|
|
12
|
+
* 8 MiB per-op byte cap; `getSignedUrl` stays the local stub. See
|
|
13
|
+
* the remote arm section below.
|
|
14
|
+
*
|
|
15
|
+
* - **Sandbox path** — returns an in-process {@link Storage} backed
|
|
16
|
+
* by an in-memory `Map<bucketName, Map<path, FileEntry>>`. State
|
|
17
|
+
* lives on the {@link Sandbox} via a `WeakMap`, so `sandbox.reset()`
|
|
18
|
+
* wipes it alongside Firestore / Auth state. Multi-bucket isolation
|
|
19
|
+
* is real — buckets are independent maps.
|
|
20
|
+
*
|
|
21
|
+
* Supported sandbox surface (the minimum a session-archive flow
|
|
22
|
+
* needs):
|
|
23
|
+
* - `storage.bucket(name?)` → {@link Bucket}-shaped handle
|
|
24
|
+
* - `bucket.file(path)` → {@link File}-shaped handle
|
|
25
|
+
* - `file.save(data, options?)` — `Buffer | string | Uint8Array`
|
|
26
|
+
* - `file.download(options?)` → `[Buffer]`
|
|
27
|
+
* - `file.delete()` — idempotent
|
|
28
|
+
* - `file.exists()` → `[boolean]`
|
|
29
|
+
* - `file.getSignedUrl(options)` → `['pyric-sandbox-storage://…']`
|
|
30
|
+
*
|
|
31
|
+
* **Deferred in the sandbox backend** (throws `"not implemented in
|
|
32
|
+
* pyric-admin/storage sandbox backend"`): streaming uploads
|
|
33
|
+
* (`createWriteStream`), resumable uploads, signed cookies, IAM
|
|
34
|
+
* policies, lifecycle rules, ACLs, copy/move, notifications.
|
|
35
|
+
*/
|
|
36
|
+
import { type PyricAdminApp } from '../app/index.js';
|
|
37
|
+
/**
|
|
38
|
+
* `pyric-admin/storage`'s sandbox `Storage` handle. It exposes the subset
|
|
39
|
+
* documented in the module header.
|
|
40
|
+
*
|
|
41
|
+
* The shared `bucket(name?)` shape is the contract — consumers code
|
|
42
|
+
* against it without caring whether the local or remote sandbox is live.
|
|
43
|
+
*/
|
|
44
|
+
export interface Storage {
|
|
45
|
+
/**
|
|
46
|
+
* Get a {@link Bucket} handle. When `name` is omitted, returns the
|
|
47
|
+
* sandbox default bucket (`'pyric-default'`).
|
|
48
|
+
*/
|
|
49
|
+
bucket(name?: string): Bucket;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* A storage bucket handle implemented by both local and remote sandbox
|
|
53
|
+
* paths. Only the documented subset is supported.
|
|
54
|
+
*/
|
|
55
|
+
export interface Bucket {
|
|
56
|
+
/** Name of the bucket. Stable across `file()` lookups. */
|
|
57
|
+
readonly name: string;
|
|
58
|
+
/** Get a {@link File} handle for `path`. The file may or may not exist. */
|
|
59
|
+
file(path: string): File;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* A file handle within a bucket. Method shapes mirror
|
|
63
|
+
* `@google-cloud/storage`'s `File` (return tuples for download / exists
|
|
64
|
+
* / getSignedUrl, etc.) so common consumer code retains the familiar shape.
|
|
65
|
+
*
|
|
66
|
+
* The sandbox backend implements the methods documented here. Any
|
|
67
|
+
* other `File` method from `@google-cloud/storage` (`createWriteStream`,
|
|
68
|
+
* `createReadStream`, `copy`, `move`, `setMetadata` beyond the basic
|
|
69
|
+
* `save` options, etc.) throws on the sandbox path — see module header.
|
|
70
|
+
*/
|
|
71
|
+
export interface File {
|
|
72
|
+
/** Name (path) of the file within its bucket. */
|
|
73
|
+
readonly name: string;
|
|
74
|
+
/** Bucket the file belongs to. Same handle the `file()` call came from. */
|
|
75
|
+
readonly bucket: Bucket;
|
|
76
|
+
/**
|
|
77
|
+
* Persist `data` at this file's path. Replaces any existing content
|
|
78
|
+
* (no append semantics). `options.metadata` is stored alongside the
|
|
79
|
+
* bytes and surfaces on later reads via the in-memory state — the
|
|
80
|
+
* sandbox doesn't expose a full `Metadata` API yet, but the payload
|
|
81
|
+
* round-trips so future expansion is non-breaking.
|
|
82
|
+
*/
|
|
83
|
+
save(data: Buffer | string | Uint8Array, options?: SaveOptions): Promise<void>;
|
|
84
|
+
/**
|
|
85
|
+
* Read the file's bytes. Returns a `[Buffer]` tuple to mirror
|
|
86
|
+
* `@google-cloud/storage`'s `File.download` (which returns
|
|
87
|
+
* `[Buffer, ...]`). Throws if the file does not exist.
|
|
88
|
+
*/
|
|
89
|
+
download(options?: DownloadOptions): Promise<[Buffer]>;
|
|
90
|
+
/**
|
|
91
|
+
* Remove the file from its bucket. Idempotent — deleting a missing
|
|
92
|
+
* file is a no-op (matches `@google-cloud/storage`'s
|
|
93
|
+
* `ignoreNotFound: true`, which is the only mode the sandbox models).
|
|
94
|
+
*/
|
|
95
|
+
delete(): Promise<void>;
|
|
96
|
+
/** `[true]` if the file exists, `[false]` otherwise. Tuple shape mirrors `@google-cloud/storage`. */
|
|
97
|
+
exists(): Promise<[boolean]>;
|
|
98
|
+
/**
|
|
99
|
+
* Return a stub signed URL of the form
|
|
100
|
+
* `pyric-sandbox-storage://${path}?expires=${expires}`. The sandbox
|
|
101
|
+
* does NOT serve the URL — it's a deterministic placeholder so
|
|
102
|
+
* agent code that round-trips signed URLs (logs, fixtures, replay)
|
|
103
|
+
* sees a stable shape.
|
|
104
|
+
*/
|
|
105
|
+
getSignedUrl(options: GetSignedUrlOptions): Promise<[string]>;
|
|
106
|
+
}
|
|
107
|
+
/** Options bag for {@link File.save}. Subset of `@google-cloud/storage`'s `SaveOptions`. */
|
|
108
|
+
export interface SaveOptions {
|
|
109
|
+
/**
|
|
110
|
+
* Arbitrary metadata stored alongside the file. The sandbox stores
|
|
111
|
+
* it verbatim; consumers that need to round-trip `contentType`,
|
|
112
|
+
* `metadata.custom`, etc. get it back via internal admin tooling
|
|
113
|
+
* (not exposed on `File` itself yet).
|
|
114
|
+
*/
|
|
115
|
+
metadata?: Record<string, unknown>;
|
|
116
|
+
/**
|
|
117
|
+
* Content type hint stored on the sandbox entry.
|
|
118
|
+
* Convenience shortcut for `metadata.contentType`.
|
|
119
|
+
*/
|
|
120
|
+
contentType?: string;
|
|
121
|
+
/**
|
|
122
|
+
* `resumable: false` is the only mode the sandbox models (single-
|
|
123
|
+
* shot writes). The sandbox throws when set to `true` since resumable
|
|
124
|
+
* uploads are deferred.
|
|
125
|
+
*/
|
|
126
|
+
resumable?: boolean;
|
|
127
|
+
}
|
|
128
|
+
/** Options bag for {@link File.download}. Subset of `@google-cloud/storage`'s `DownloadOptions`. */
|
|
129
|
+
export interface DownloadOptions {
|
|
130
|
+
/** The sandbox accepts but ignores `validation`. */
|
|
131
|
+
validation?: 'md5' | 'crc32c' | boolean;
|
|
132
|
+
}
|
|
133
|
+
/** Options bag for {@link File.getSignedUrl}. Mirrors `@google-cloud/storage`'s shape. */
|
|
134
|
+
export interface GetSignedUrlOptions {
|
|
135
|
+
/** `'read' | 'write' | 'delete' | 'resumable'`. Sandbox stamps it into the URL only as a hint. */
|
|
136
|
+
action: 'read' | 'write' | 'delete' | 'resumable';
|
|
137
|
+
/**
|
|
138
|
+
* Expiration. Accepts ms-since-epoch (number), ISO date string, or
|
|
139
|
+
* `Date`. Sandbox normalizes to ms-since-epoch and embeds in the
|
|
140
|
+
* stub URL's `expires=` query.
|
|
141
|
+
*/
|
|
142
|
+
expires: number | string | Date;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Input accepted by {@link getStorage}. The branded `PyricAdminApp` is
|
|
146
|
+
* the canonical shape; calling without an argument resolves the default
|
|
147
|
+
* app from the `pyric-admin/app` registry (mirroring
|
|
148
|
+
* `firebase-admin/storage`, where `getStorage()` resolves the default App),
|
|
149
|
+
* and throws the captured `app/no-app` error when nothing is initialized.
|
|
150
|
+
*/
|
|
151
|
+
export type StorageApp = PyricAdminApp;
|
|
152
|
+
/**
|
|
153
|
+
* Get the {@link Storage} service for the given app.
|
|
154
|
+
*
|
|
155
|
+
* Returns a sandbox-backed `Storage` whose state
|
|
156
|
+
* lives on the `Sandbox`. `sandbox.reset()` wipes it.
|
|
157
|
+
*/
|
|
158
|
+
export declare function getStorage(app?: StorageApp): Storage;
|
|
159
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AASH,OAAO,EAGL,KAAK,aAAa,EAEnB,MAAM,iBAAiB,CAAC;AAKzB;;;;;;GAMG;AACH,MAAM,WAAW,OAAO;IACtB;;;OAGG;IACH,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC/B;AAED;;;GAGG;AACH,MAAM,WAAW,MAAM;IACrB,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,2EAA2E;IAC3E,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,IAAI;IACnB,iDAAiD;IACjD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;;;OAMG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,UAAU,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/E;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IACvD;;;;OAIG;IACH,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,qGAAqG;IACrG,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAC7B;;;;;;OAMG;IACH,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;CAC/D;AAED,4FAA4F;AAC5F,MAAM,WAAW,WAAW;IAC1B;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,oGAAoG;AACpG,MAAM,WAAW,eAAe;IAC9B,oDAAoD;IACpD,UAAU,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC;CACzC;AAED,0FAA0F;AAC1F,MAAM,WAAW,mBAAmB;IAClC,kGAAkG;IAClG,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,WAAW,CAAC;IAClD;;;;OAIG;IACH,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CACjC;AAED;;;;;;GAMG;AACH,MAAM,MAAM,UAAU,GAAG,aAAa,CAAC;AAEvC;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,GAAG,CAAC,EAAE,UAAU,GAAG,OAAO,CAuBpD"}
|
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `pyric-admin/storage` — sandbox mirror for the Admin Storage shape.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the useful `firebase-admin/storage` shape for local and remote
|
|
5
|
+
* sandbox apps selected at {@link initializeApp} time. Dispatch reads the
|
|
6
|
+
* {@link ADMIN_APP_TARGET} brand on the `PyricAdminApp` handle.
|
|
7
|
+
*
|
|
8
|
+
* - **Remote sandbox path** — a handle branded by `@pyric/cli`'
|
|
9
|
+
* `connectRemoteSandbox()`/`remoteSandbox()` relays every data
|
|
10
|
+
* operation over the bridge to the browser-hosted SharedWorker's
|
|
11
|
+
* object store (admin lens pinned — rules bypass). Single bucket;
|
|
12
|
+
* 8 MiB per-op byte cap; `getSignedUrl` stays the local stub. See
|
|
13
|
+
* the remote arm section below.
|
|
14
|
+
*
|
|
15
|
+
* - **Sandbox path** — returns an in-process {@link Storage} backed
|
|
16
|
+
* by an in-memory `Map<bucketName, Map<path, FileEntry>>`. State
|
|
17
|
+
* lives on the {@link Sandbox} via a `WeakMap`, so `sandbox.reset()`
|
|
18
|
+
* wipes it alongside Firestore / Auth state. Multi-bucket isolation
|
|
19
|
+
* is real — buckets are independent maps.
|
|
20
|
+
*
|
|
21
|
+
* Supported sandbox surface (the minimum a session-archive flow
|
|
22
|
+
* needs):
|
|
23
|
+
* - `storage.bucket(name?)` → {@link Bucket}-shaped handle
|
|
24
|
+
* - `bucket.file(path)` → {@link File}-shaped handle
|
|
25
|
+
* - `file.save(data, options?)` — `Buffer | string | Uint8Array`
|
|
26
|
+
* - `file.download(options?)` → `[Buffer]`
|
|
27
|
+
* - `file.delete()` — idempotent
|
|
28
|
+
* - `file.exists()` → `[boolean]`
|
|
29
|
+
* - `file.getSignedUrl(options)` → `['pyric-sandbox-storage://…']`
|
|
30
|
+
*
|
|
31
|
+
* **Deferred in the sandbox backend** (throws `"not implemented in
|
|
32
|
+
* pyric-admin/storage sandbox backend"`): streaming uploads
|
|
33
|
+
* (`createWriteStream`), resumable uploads, signed cookies, IAM
|
|
34
|
+
* policies, lifecycle rules, ACLs, copy/move, notifications.
|
|
35
|
+
*/
|
|
36
|
+
import { isRemoteSandbox, } from 'pyric/sandbox';
|
|
37
|
+
import { ADMIN_APP_TARGET, getApp, } from '../app/index.js';
|
|
38
|
+
import { assertAdminAppActive } from '../app/lifecycle.js';
|
|
39
|
+
/**
|
|
40
|
+
* Get the {@link Storage} service for the given app.
|
|
41
|
+
*
|
|
42
|
+
* Returns a sandbox-backed `Storage` whose state
|
|
43
|
+
* lives on the `Sandbox`. `sandbox.reset()` wipes it.
|
|
44
|
+
*/
|
|
45
|
+
export function getStorage(app) {
|
|
46
|
+
// No-arg call resolves the default app; nothing initialized → captured
|
|
47
|
+
// `app/no-app` FirebaseAppError (see pyric-admin/app getApp).
|
|
48
|
+
const resolved = app === undefined ? getApp() : app;
|
|
49
|
+
assertAdminAppActive(resolved);
|
|
50
|
+
if (resolved[ADMIN_APP_TARGET] === 'sandbox') {
|
|
51
|
+
// Remote brand checked BEFORE the local arm (same dispatch order as
|
|
52
|
+
// auth/database): the local arm's WeakMap state + `onEvent` reset hook
|
|
53
|
+
// must never touch a remote handle — local state keyed off a remote
|
|
54
|
+
// handle would be a private server-side store the browser never sees,
|
|
55
|
+
// and `onEvent` throws on remote handles by design.
|
|
56
|
+
if (isRemoteSandbox(resolved.sandbox)) {
|
|
57
|
+
return getRemoteStorage(resolved.sandbox);
|
|
58
|
+
}
|
|
59
|
+
return getSandboxStorage(resolved);
|
|
60
|
+
}
|
|
61
|
+
// Defensive: the union is closed at the type level. A runtime value
|
|
62
|
+
// that lands here means a caller forged a handle without going
|
|
63
|
+
// through `initializeApp`.
|
|
64
|
+
throw new TypeError('pyric-admin/storage: getStorage expected a PyricAdminApp from `initializeApp`; ' +
|
|
65
|
+
'received a value with no recognized ADMIN_APP_TARGET brand.');
|
|
66
|
+
}
|
|
67
|
+
// ─── Sandbox path ───────────────────────────────────────────────────────
|
|
68
|
+
/**
|
|
69
|
+
* Default sandbox bucket name. Matches the `pyric-default` used by the
|
|
70
|
+
* `pyric/storage` modular sandbox so consumers that switch between
|
|
71
|
+
* surfaces don't see an unexpected bucket name change.
|
|
72
|
+
*/
|
|
73
|
+
const DEFAULT_SANDBOX_BUCKET = 'pyric-default';
|
|
74
|
+
/**
|
|
75
|
+
* State + reset-handler registry keyed on `Sandbox` so a single
|
|
76
|
+
* Sandbox shares its storage across every `getStorage` call. The
|
|
77
|
+
* `WeakMap` lets a discarded `Sandbox` (and its state) be GC'd
|
|
78
|
+
* naturally.
|
|
79
|
+
*/
|
|
80
|
+
const SANDBOX_STATE = new WeakMap();
|
|
81
|
+
/**
|
|
82
|
+
* Reset-subscription bookkeeping. We subscribe to `sandbox.onEvent`
|
|
83
|
+
* once per Sandbox and re-create the bucket map on
|
|
84
|
+
* `session_boundary` events with `phase: 'reset'`. Without this,
|
|
85
|
+
* `sandbox.reset()` would wipe Firestore but leave storage untouched —
|
|
86
|
+
* a leak the sandbox model deliberately avoids.
|
|
87
|
+
*/
|
|
88
|
+
const RESET_HOOKED = new WeakSet();
|
|
89
|
+
function ensureBucketMap(sandbox) {
|
|
90
|
+
let map = SANDBOX_STATE.get(sandbox);
|
|
91
|
+
if (!map) {
|
|
92
|
+
map = new Map();
|
|
93
|
+
SANDBOX_STATE.set(sandbox, map);
|
|
94
|
+
}
|
|
95
|
+
if (!RESET_HOOKED.has(sandbox)) {
|
|
96
|
+
RESET_HOOKED.add(sandbox);
|
|
97
|
+
sandbox.onEvent((event) => {
|
|
98
|
+
if (event.kind === 'session_boundary' && event.phase === 'reset') {
|
|
99
|
+
// Replace the map in place so existing Storage / Bucket / File
|
|
100
|
+
// handles keep working but observe an empty state.
|
|
101
|
+
const existing = SANDBOX_STATE.get(sandbox);
|
|
102
|
+
if (existing)
|
|
103
|
+
existing.clear();
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
return map;
|
|
108
|
+
}
|
|
109
|
+
function getSandboxStorage(app) {
|
|
110
|
+
const sandbox = app.sandbox;
|
|
111
|
+
const buckets = ensureBucketMap(sandbox);
|
|
112
|
+
return new SandboxStorage(buckets);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Sandbox `Storage` implementation. Holds a reference to the per-
|
|
116
|
+
* sandbox bucket map; each `bucket()` call returns a fresh `Bucket`
|
|
117
|
+
* handle bound to the same underlying map, mirroring how
|
|
118
|
+
* `@google-cloud/storage` returns lightweight per-call handles.
|
|
119
|
+
*/
|
|
120
|
+
class SandboxStorage {
|
|
121
|
+
buckets;
|
|
122
|
+
constructor(buckets) {
|
|
123
|
+
this.buckets = buckets;
|
|
124
|
+
}
|
|
125
|
+
bucket(name) {
|
|
126
|
+
const bucketName = name ?? DEFAULT_SANDBOX_BUCKET;
|
|
127
|
+
let files = this.buckets.get(bucketName);
|
|
128
|
+
if (!files) {
|
|
129
|
+
files = new Map();
|
|
130
|
+
this.buckets.set(bucketName, files);
|
|
131
|
+
}
|
|
132
|
+
return new SandboxBucket(bucketName, files);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
class SandboxBucket {
|
|
136
|
+
name;
|
|
137
|
+
files;
|
|
138
|
+
constructor(name, files) {
|
|
139
|
+
this.name = name;
|
|
140
|
+
this.files = files;
|
|
141
|
+
}
|
|
142
|
+
file(path) {
|
|
143
|
+
return new SandboxFile(path, this, this.files);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
class SandboxFile {
|
|
147
|
+
name;
|
|
148
|
+
bucket;
|
|
149
|
+
files;
|
|
150
|
+
constructor(name, bucket, files) {
|
|
151
|
+
this.name = name;
|
|
152
|
+
this.bucket = bucket;
|
|
153
|
+
this.files = files;
|
|
154
|
+
}
|
|
155
|
+
async save(data, options = {}) {
|
|
156
|
+
if (options.resumable === true) {
|
|
157
|
+
throw new Error('not implemented in pyric-admin/storage sandbox backend: resumable uploads');
|
|
158
|
+
}
|
|
159
|
+
const bytes = toBytes(data);
|
|
160
|
+
const metadata = options.metadata ?? {};
|
|
161
|
+
const entry = {
|
|
162
|
+
data: bytes,
|
|
163
|
+
metadata,
|
|
164
|
+
...(options.contentType !== undefined ? { contentType: options.contentType } : {}),
|
|
165
|
+
};
|
|
166
|
+
this.files.set(this.name, entry);
|
|
167
|
+
}
|
|
168
|
+
async download(_options = {}) {
|
|
169
|
+
const entry = this.files.get(this.name);
|
|
170
|
+
if (!entry) {
|
|
171
|
+
// Mirror the gcs/firebase-admin error message shape so consumer
|
|
172
|
+
// catch-blocks that string-match `No such object` keep working.
|
|
173
|
+
throw new Error(`No such object: ${this.bucket.name}/${this.name}`);
|
|
174
|
+
}
|
|
175
|
+
return [Buffer.from(entry.data)];
|
|
176
|
+
}
|
|
177
|
+
async delete() {
|
|
178
|
+
this.files.delete(this.name);
|
|
179
|
+
}
|
|
180
|
+
async exists() {
|
|
181
|
+
return [this.files.has(this.name)];
|
|
182
|
+
}
|
|
183
|
+
async getSignedUrl(options) {
|
|
184
|
+
return [stubSignedUrl(this.bucket.name, this.name, options)];
|
|
185
|
+
}
|
|
186
|
+
// ─── Deferred surface (declared so TS callers see a clear error) ────
|
|
187
|
+
/** @deprecated Streaming writes are deferred — see module header. */
|
|
188
|
+
createWriteStream() {
|
|
189
|
+
throw new Error('not implemented in pyric-admin/storage sandbox backend: createWriteStream');
|
|
190
|
+
}
|
|
191
|
+
/** @deprecated Streaming reads are deferred — see module header. */
|
|
192
|
+
createReadStream() {
|
|
193
|
+
throw new Error('not implemented in pyric-admin/storage sandbox backend: createReadStream');
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
// ─── Remote sandbox arm (remote sandbox, slice 2) ───────────────────────
|
|
197
|
+
//
|
|
198
|
+
// The app's `Sandbox` is a Node-side handle onto the browser-hosted
|
|
199
|
+
// SharedWorker sandbox. Every data operation relays over the handle's
|
|
200
|
+
// worker channel with `actAs: { mode: 'admin' }` pinned — firebase-admin's
|
|
201
|
+
// rules-bypass semantics against the ONE object store the app + Studio +
|
|
202
|
+
// agents share (the host resolves the lens to `pyric/storage/internal`'s
|
|
203
|
+
// admin plane). There is deliberately NO local state here: a `WeakMap`
|
|
204
|
+
// bucket map keyed off a remote handle would be private server-side data
|
|
205
|
+
// the browser never sees, and the local arm's `onEvent` reset hook throws
|
|
206
|
+
// on remote handles by design.
|
|
207
|
+
//
|
|
208
|
+
// Divergences from the local arm, all LOUD:
|
|
209
|
+
// - single bucket: the worker's `pyric/storage` store is single-bucket
|
|
210
|
+
// ("the data store is shared" — bucket names only round-trip in
|
|
211
|
+
// metadata), so `bucket('non-default')` throws instead of silently
|
|
212
|
+
// merging buckets. The default bucket name matches the local arm.
|
|
213
|
+
// - byte payloads are capped at 8 MiB per op (whole-object buffering
|
|
214
|
+
// over four relay hops; streaming stays unsupported on both sandbox arms).
|
|
215
|
+
// `getSignedUrl` does NOT relay: it stays the byte-identical local stub.
|
|
216
|
+
/** firebase-admin's rules-bypass lens, pinned on every relayed operation. */
|
|
217
|
+
const STORAGE_REMOTE_ADMIN_LENS = { mode: 'admin' };
|
|
218
|
+
/**
|
|
219
|
+
* Raw per-op byte cap for relayed storage payloads. MUST mirror
|
|
220
|
+
* `@pyric/cli`' `MAX_STORAGE_OP_BYTES` (serve/worker/protocol.ts) — the
|
|
221
|
+
* worker host enforces the same cap on its end. Inlined (like the RTDB
|
|
222
|
+
* push-id generator) because `pyric-admin` deliberately does not depend on
|
|
223
|
+
* `@pyric/cli`.
|
|
224
|
+
*/
|
|
225
|
+
const MAX_REMOTE_STORAGE_OP_BYTES = 8 * 1024 * 1024;
|
|
226
|
+
/** One remote `Storage` per remote handle (handles only — never data). */
|
|
227
|
+
const remoteStorageBySandbox = new WeakMap();
|
|
228
|
+
function getRemoteStorage(sandbox) {
|
|
229
|
+
let storage = remoteStorageBySandbox.get(sandbox);
|
|
230
|
+
if (!storage) {
|
|
231
|
+
storage = new RemoteStorage(sandbox.channel);
|
|
232
|
+
remoteStorageBySandbox.set(sandbox, storage);
|
|
233
|
+
}
|
|
234
|
+
return storage;
|
|
235
|
+
}
|
|
236
|
+
class RemoteStorage {
|
|
237
|
+
channel;
|
|
238
|
+
constructor(channel) {
|
|
239
|
+
this.channel = channel;
|
|
240
|
+
}
|
|
241
|
+
bucket(name) {
|
|
242
|
+
// The worker's object store is single-bucket. A non-default name can't
|
|
243
|
+
// be faithfully relayed — throw loudly instead of silently merging
|
|
244
|
+
// buckets (the local arm has REAL multi-bucket isolation; this is the
|
|
245
|
+
// sharpest local/remote divergence, so it must be explicit).
|
|
246
|
+
if (name !== undefined && name !== DEFAULT_SANDBOX_BUCKET) {
|
|
247
|
+
throw new Error(`pyric-admin/storage: the remote (browser) sandbox has a single bucket — ` +
|
|
248
|
+
`bucket('${name}') cannot be isolated. Use bucket() (the default ` +
|
|
249
|
+
`'${DEFAULT_SANDBOX_BUCKET}' bucket) instead.`);
|
|
250
|
+
}
|
|
251
|
+
return new RemoteBucket(DEFAULT_SANDBOX_BUCKET, this.channel);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
class RemoteBucket {
|
|
255
|
+
name;
|
|
256
|
+
channel;
|
|
257
|
+
constructor(name, channel) {
|
|
258
|
+
this.name = name;
|
|
259
|
+
this.channel = channel;
|
|
260
|
+
}
|
|
261
|
+
file(path) {
|
|
262
|
+
return new RemoteFile(path, this, this.channel);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
class RemoteFile {
|
|
266
|
+
name;
|
|
267
|
+
bucket;
|
|
268
|
+
channel;
|
|
269
|
+
constructor(name, bucket, channel) {
|
|
270
|
+
this.name = name;
|
|
271
|
+
this.bucket = bucket;
|
|
272
|
+
this.channel = channel;
|
|
273
|
+
}
|
|
274
|
+
async save(data, options = {}) {
|
|
275
|
+
if (options.resumable === true) {
|
|
276
|
+
throw new Error('not implemented in pyric-admin/storage remote sandbox backend: resumable uploads');
|
|
277
|
+
}
|
|
278
|
+
const bytes = toBytes(data);
|
|
279
|
+
if (bytes.byteLength > MAX_REMOTE_STORAGE_OP_BYTES) {
|
|
280
|
+
throw payloadTooLarge(bytes.byteLength, `save() payload for '${this.name}'`);
|
|
281
|
+
}
|
|
282
|
+
await this.channel.op({
|
|
283
|
+
method: 'storage.putBytes',
|
|
284
|
+
path: this.name,
|
|
285
|
+
dataB64: Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString('base64'),
|
|
286
|
+
...(options.contentType !== undefined ? { contentType: options.contentType } : {}),
|
|
287
|
+
...(options.metadata !== undefined ? { metadata: options.metadata } : {}),
|
|
288
|
+
actAs: STORAGE_REMOTE_ADMIN_LENS,
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
async download(_options = {}) {
|
|
292
|
+
let wire;
|
|
293
|
+
try {
|
|
294
|
+
wire = (await this.channel.op({
|
|
295
|
+
method: 'storage.getBytes',
|
|
296
|
+
path: this.name,
|
|
297
|
+
actAs: STORAGE_REMOTE_ADMIN_LENS,
|
|
298
|
+
}));
|
|
299
|
+
}
|
|
300
|
+
catch (err) {
|
|
301
|
+
if (isObjectNotFound(err)) {
|
|
302
|
+
// Mirror the gcs/firebase-admin (and local arm) message shape so
|
|
303
|
+
// consumer catch-blocks that string-match `No such object` work
|
|
304
|
+
// identically across arms.
|
|
305
|
+
throw new Error(`No such object: ${this.bucket.name}/${this.name}`);
|
|
306
|
+
}
|
|
307
|
+
throw err;
|
|
308
|
+
}
|
|
309
|
+
return [Buffer.from(wire.dataB64, 'base64')];
|
|
310
|
+
}
|
|
311
|
+
async delete() {
|
|
312
|
+
try {
|
|
313
|
+
await this.channel.op({
|
|
314
|
+
method: 'storage.deleteObject',
|
|
315
|
+
path: this.name,
|
|
316
|
+
actAs: STORAGE_REMOTE_ADMIN_LENS,
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
catch (err) {
|
|
320
|
+
// The worker store's delete is already idempotent, but swallow a
|
|
321
|
+
// not-found defensively so the local arm's idempotent-delete contract
|
|
322
|
+
// holds even if `pyric/storage` adopts stricter delete semantics later.
|
|
323
|
+
if (isObjectNotFound(err))
|
|
324
|
+
return;
|
|
325
|
+
throw err;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
async exists() {
|
|
329
|
+
try {
|
|
330
|
+
await this.channel.op({
|
|
331
|
+
method: 'storage.getMetadata',
|
|
332
|
+
path: this.name,
|
|
333
|
+
actAs: STORAGE_REMOTE_ADMIN_LENS,
|
|
334
|
+
});
|
|
335
|
+
return [true];
|
|
336
|
+
}
|
|
337
|
+
catch (err) {
|
|
338
|
+
if (isObjectNotFound(err))
|
|
339
|
+
return [false];
|
|
340
|
+
throw err;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
/** Local stub — byte-identical to the local arm's (no data needed, so it
|
|
344
|
+
* never relays). The sandbox does NOT serve the URL. */
|
|
345
|
+
async getSignedUrl(options) {
|
|
346
|
+
return [stubSignedUrl(this.bucket.name, this.name, options)];
|
|
347
|
+
}
|
|
348
|
+
// ─── Deferred surface (remediating throws, remote-flavored) ─────────
|
|
349
|
+
createWriteStream() {
|
|
350
|
+
throw new Error('not implemented in pyric-admin/storage remote sandbox backend: createWriteStream — ' +
|
|
351
|
+
'streams cannot span the bridge relay; use file.save(buffer) (≤ 8 MiB) instead.');
|
|
352
|
+
}
|
|
353
|
+
createReadStream() {
|
|
354
|
+
throw new Error('not implemented in pyric-admin/storage remote sandbox backend: createReadStream — ' +
|
|
355
|
+
'streams cannot span the bridge relay; use file.download() (≤ 8 MiB) instead.');
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
/** Is this relayed error the worker's `storage/object-not-found`? */
|
|
359
|
+
function isObjectNotFound(err) {
|
|
360
|
+
return err?.code === 'storage/object-not-found';
|
|
361
|
+
}
|
|
362
|
+
/** Over-cap rejection (code `payload-too-large`) — mirrors the worker host's
|
|
363
|
+
* message shape and names the streaming gap. */
|
|
364
|
+
function payloadTooLarge(sizeBytes, what) {
|
|
365
|
+
const err = new Error(`pyric-admin/storage: ${what} is ${sizeBytes} bytes — over the ` +
|
|
366
|
+
`${MAX_REMOTE_STORAGE_OP_BYTES / (1024 * 1024)} MiB remote storage op cap. ` +
|
|
367
|
+
'Streaming/resumable transfers are not supported on the sandbox backend; ' +
|
|
368
|
+
'split the object or keep it under the cap.');
|
|
369
|
+
err.code = 'payload-too-large';
|
|
370
|
+
return err;
|
|
371
|
+
}
|
|
372
|
+
// ─── Helpers ────────────────────────────────────────────────────────────
|
|
373
|
+
/**
|
|
374
|
+
* The deterministic sandbox signed-URL stub, shared by the local and remote
|
|
375
|
+
* arms so their output is byte-identical (the URL is never served — it's a
|
|
376
|
+
* stable placeholder for logs/fixtures/replay).
|
|
377
|
+
*/
|
|
378
|
+
function stubSignedUrl(bucketName, path, options) {
|
|
379
|
+
const expiresMs = normalizeExpires(options.expires);
|
|
380
|
+
return `pyric-sandbox-storage://${bucketName}/${path}?expires=${expiresMs}&action=${options.action}`;
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Normalize `Buffer | string | Uint8Array` into a fresh `Uint8Array`.
|
|
384
|
+
* We copy on ingest so callers can mutate their input buffer without
|
|
385
|
+
* corrupting stored state — mirrors how `firebase-admin/storage` /
|
|
386
|
+
* `@google-cloud/storage` treat `save` inputs.
|
|
387
|
+
*/
|
|
388
|
+
function toBytes(data) {
|
|
389
|
+
if (typeof data === 'string') {
|
|
390
|
+
return new TextEncoder().encode(data);
|
|
391
|
+
}
|
|
392
|
+
// Both Buffer (Node) and Uint8Array land here — copy into a new
|
|
393
|
+
// Uint8Array so the stored bytes are independent of the caller's
|
|
394
|
+
// reference. `slice()` produces a copy in both cases.
|
|
395
|
+
return new Uint8Array(data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength));
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Normalize the `expires` field into ms-since-epoch. Mirrors the
|
|
399
|
+
* accepted shapes from `@google-cloud/storage`'s `GetSignedUrlOptions`.
|
|
400
|
+
* The sandbox doesn't enforce expiration — the value is only embedded
|
|
401
|
+
* in the stub URL so consumers can round-trip it.
|
|
402
|
+
*/
|
|
403
|
+
function normalizeExpires(expires) {
|
|
404
|
+
if (typeof expires === 'number')
|
|
405
|
+
return expires;
|
|
406
|
+
if (expires instanceof Date)
|
|
407
|
+
return expires.getTime();
|
|
408
|
+
// String form — accept anything `Date` parses. Bogus input becomes
|
|
409
|
+
// `NaN`, which is still embeddable in the URL; we don't enforce
|
|
410
|
+
// strictness because the value only feeds the deterministic sandbox stub.
|
|
411
|
+
return new Date(expires).getTime();
|
|
412
|
+
}
|
|
413
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pyric-admin",
|
|
3
|
+
"version": "0.1.0-alpha.10",
|
|
4
|
+
"license": "Apache-2.0",
|
|
5
|
+
"homepage": "https://pyric.dev",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/davideast/pyric.git",
|
|
9
|
+
"directory": "packages/pyric-admin"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/davideast/pyric/issues"
|
|
13
|
+
},
|
|
14
|
+
"description": "Firebase Admin-shaped adapters for the Pyric development sandbox.",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"exports": {
|
|
17
|
+
"./app": {
|
|
18
|
+
"types": "./dist/app/index.d.ts",
|
|
19
|
+
"import": "./dist/app/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./firestore": {
|
|
22
|
+
"types": "./dist/firestore/index.d.ts",
|
|
23
|
+
"import": "./dist/firestore/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./auth": {
|
|
26
|
+
"types": "./dist/auth/index.d.ts",
|
|
27
|
+
"import": "./dist/auth/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./database": {
|
|
30
|
+
"types": "./dist/database/index.d.ts",
|
|
31
|
+
"import": "./dist/database/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./storage": {
|
|
34
|
+
"types": "./dist/storage/index.d.ts",
|
|
35
|
+
"import": "./dist/storage/index.js"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"dist",
|
|
40
|
+
"README.md",
|
|
41
|
+
"LICENSE"
|
|
42
|
+
],
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "tsc",
|
|
45
|
+
"test": "bun test",
|
|
46
|
+
"typecheck": "bun x tsc -p tsconfig.json --noEmit"
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"pyric": "^0.1.0-alpha.10"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@types/bun": "latest",
|
|
53
|
+
"firebase-admin": "^13.0.0",
|
|
54
|
+
"typescript": "^5.7.0",
|
|
55
|
+
"fake-indexeddb": "^6.0.0"
|
|
56
|
+
},
|
|
57
|
+
"engines": {
|
|
58
|
+
"node": ">=22"
|
|
59
|
+
},
|
|
60
|
+
"publishConfig": {
|
|
61
|
+
"access": "public"
|
|
62
|
+
}
|
|
63
|
+
}
|