pyric-admin 0.1.0-alpha.7
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/README.md +49 -0
- package/dist/app/index.d.ts +158 -0
- package/dist/app/index.d.ts.map +1 -0
- package/dist/app/index.js +297 -0
- package/dist/app/index.js.map +1 -0
- package/dist/auth/index.d.ts +146 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +785 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/database/index.d.ts +119 -0
- package/dist/database/index.d.ts.map +1 -0
- package/dist/database/index.js +965 -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 +53 -0
- package/dist/firestore/index.js.map +1 -0
- package/dist/storage/index.d.ts +178 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +442 -0
- package/dist/storage/index.js.map +1 -0
- package/package.json +52 -0
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `pyric-admin/storage` — Phase 3 + Phase 4b implementation.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors `firebase-admin/storage` with sandbox + prod backends, both
|
|
5
|
+
* selected at {@link initializeApp} time on `pyric-admin/app` (ADR-001
|
|
6
|
+
* D6). Dispatch reads the {@link ADMIN_APP_TARGET} brand on the
|
|
7
|
+
* `PyricAdminApp` handle — no structural duck-typing, no per-call
|
|
8
|
+
* shape probing.
|
|
9
|
+
*
|
|
10
|
+
* - **Prod path** — delegates to `firebase-admin/storage`'s
|
|
11
|
+
* `getStorage(adminApp)`. The returned object is the genuine
|
|
12
|
+
* production `Storage`, so every method on `Storage` / `Bucket` /
|
|
13
|
+
* `File` (from `@google-cloud/storage`) is present unchanged.
|
|
14
|
+
*
|
|
15
|
+
* - **Remote sandbox path** — a handle branded by `pyric-tools`'
|
|
16
|
+
* `connectRemoteSandbox()`/`remoteSandbox()` relays every data
|
|
17
|
+
* operation over the bridge to the browser-hosted SharedWorker's
|
|
18
|
+
* object store (admin lens pinned — rules bypass). Single bucket;
|
|
19
|
+
* 8 MiB per-op byte cap; `getSignedUrl` stays the local stub. See
|
|
20
|
+
* the remote arm section below.
|
|
21
|
+
*
|
|
22
|
+
* - **Sandbox path** — returns an in-process {@link Storage} backed
|
|
23
|
+
* by an in-memory `Map<bucketName, Map<path, FileEntry>>`. State
|
|
24
|
+
* lives on the {@link Sandbox} via a `WeakMap`, so `sandbox.reset()`
|
|
25
|
+
* wipes it alongside Firestore / Auth state. Multi-bucket isolation
|
|
26
|
+
* is real — buckets are independent maps.
|
|
27
|
+
*
|
|
28
|
+
* Supported sandbox surface (the minimum a session-archive flow
|
|
29
|
+
* needs):
|
|
30
|
+
* - `storage.bucket(name?)` → {@link Bucket}-shaped handle
|
|
31
|
+
* - `bucket.file(path)` → {@link File}-shaped handle
|
|
32
|
+
* - `file.save(data, options?)` — `Buffer | string | Uint8Array`
|
|
33
|
+
* - `file.download(options?)` → `[Buffer]`
|
|
34
|
+
* - `file.delete()` — idempotent
|
|
35
|
+
* - `file.exists()` → `[boolean]`
|
|
36
|
+
* - `file.getSignedUrl(options)` → `['pyric-sandbox-storage://…']`
|
|
37
|
+
*
|
|
38
|
+
* **Deferred in the sandbox backend** (throws `"not implemented in
|
|
39
|
+
* pyric-admin/storage sandbox backend"`): streaming uploads
|
|
40
|
+
* (`createWriteStream`), resumable uploads, signed cookies, IAM
|
|
41
|
+
* policies, lifecycle rules, ACLs, copy/move, notifications. The
|
|
42
|
+
* prod path keeps every one of these — only the sandbox stub omits
|
|
43
|
+
* them.
|
|
44
|
+
*/
|
|
45
|
+
import { getStorage as getProdStorage } from 'firebase-admin/storage';
|
|
46
|
+
import { isRemoteSandbox, } from 'pyric/sandbox';
|
|
47
|
+
import { ADMIN_APP_TARGET, getApp, } from '../app/index.js';
|
|
48
|
+
/**
|
|
49
|
+
* Get the {@link Storage} service for the given app.
|
|
50
|
+
*
|
|
51
|
+
* - **Prod app** → returns `firebase-admin/storage`'s `Storage` for
|
|
52
|
+
* the underlying `adminApp`. Drop-in compatible with production
|
|
53
|
+
* code that uses `firebase-admin/storage` directly.
|
|
54
|
+
* - **Sandbox app** → returns a sandbox-backed `Storage` whose state
|
|
55
|
+
* lives on the `Sandbox`. `sandbox.reset()` wipes it.
|
|
56
|
+
*/
|
|
57
|
+
export function getStorage(app) {
|
|
58
|
+
// No-arg call resolves the default app; nothing initialized → captured
|
|
59
|
+
// `app/no-app` FirebaseAppError (see pyric-admin/app getApp).
|
|
60
|
+
const resolved = app === undefined ? getApp() : app;
|
|
61
|
+
if (resolved[ADMIN_APP_TARGET] === 'sandbox') {
|
|
62
|
+
// Remote brand checked BEFORE the local arm (same dispatch order as
|
|
63
|
+
// auth/database): the local arm's WeakMap state + `onEvent` reset hook
|
|
64
|
+
// must never touch a remote handle — local state keyed off a remote
|
|
65
|
+
// handle would be a private server-side store the browser never sees,
|
|
66
|
+
// and `onEvent` throws on remote handles by design.
|
|
67
|
+
if (isRemoteSandbox(resolved.sandbox)) {
|
|
68
|
+
return getRemoteStorage(resolved.sandbox);
|
|
69
|
+
}
|
|
70
|
+
return getSandboxStorage(resolved);
|
|
71
|
+
}
|
|
72
|
+
if (resolved[ADMIN_APP_TARGET] === 'prod') {
|
|
73
|
+
return getProdStorageHandle(resolved);
|
|
74
|
+
}
|
|
75
|
+
// Defensive: the union is closed at the type level. A runtime value
|
|
76
|
+
// that lands here means a caller forged a handle without going
|
|
77
|
+
// through `initializeApp`.
|
|
78
|
+
throw new TypeError('pyric-admin/storage: getStorage expected a PyricAdminApp from `initializeApp`; ' +
|
|
79
|
+
'received a value with no recognized ADMIN_APP_TARGET brand.');
|
|
80
|
+
}
|
|
81
|
+
// ─── Prod path ──────────────────────────────────────────────────────────
|
|
82
|
+
/**
|
|
83
|
+
* Resolve the prod path. The returned `Storage` is the unmodified
|
|
84
|
+
* `firebase-admin/storage` handle — every `Bucket` / `File` method
|
|
85
|
+
* works exactly as documented in `@google-cloud/storage`.
|
|
86
|
+
*
|
|
87
|
+
* We assert-cast the result to our local {@link Storage} interface:
|
|
88
|
+
* structurally it's a superset (same `bucket(name?)` shape) and
|
|
89
|
+
* exposing the broader surface gives callers full access without
|
|
90
|
+
* forcing them back into a `firebase-admin/storage` import.
|
|
91
|
+
*/
|
|
92
|
+
function getProdStorageHandle(app) {
|
|
93
|
+
const prod = getProdStorage(app.adminApp);
|
|
94
|
+
return prod;
|
|
95
|
+
}
|
|
96
|
+
// ─── Sandbox path ───────────────────────────────────────────────────────
|
|
97
|
+
/**
|
|
98
|
+
* Default sandbox bucket name. Matches the `pyric-default` used by the
|
|
99
|
+
* `pyric/storage` modular sandbox so consumers that switch between
|
|
100
|
+
* surfaces don't see an unexpected bucket name change.
|
|
101
|
+
*/
|
|
102
|
+
const DEFAULT_SANDBOX_BUCKET = 'pyric-default';
|
|
103
|
+
/**
|
|
104
|
+
* State + reset-handler registry keyed on `Sandbox` so a single
|
|
105
|
+
* Sandbox shares its storage across every `getStorage` call. The
|
|
106
|
+
* `WeakMap` lets a discarded `Sandbox` (and its state) be GC'd
|
|
107
|
+
* naturally.
|
|
108
|
+
*/
|
|
109
|
+
const SANDBOX_STATE = new WeakMap();
|
|
110
|
+
/**
|
|
111
|
+
* Reset-subscription bookkeeping. We subscribe to `sandbox.onEvent`
|
|
112
|
+
* once per Sandbox and re-create the bucket map on
|
|
113
|
+
* `session_boundary` events with `phase: 'reset'`. Without this,
|
|
114
|
+
* `sandbox.reset()` would wipe Firestore but leave storage untouched —
|
|
115
|
+
* a leak the sandbox model deliberately avoids.
|
|
116
|
+
*/
|
|
117
|
+
const RESET_HOOKED = new WeakSet();
|
|
118
|
+
function ensureBucketMap(sandbox) {
|
|
119
|
+
let map = SANDBOX_STATE.get(sandbox);
|
|
120
|
+
if (!map) {
|
|
121
|
+
map = new Map();
|
|
122
|
+
SANDBOX_STATE.set(sandbox, map);
|
|
123
|
+
}
|
|
124
|
+
if (!RESET_HOOKED.has(sandbox)) {
|
|
125
|
+
RESET_HOOKED.add(sandbox);
|
|
126
|
+
sandbox.onEvent((event) => {
|
|
127
|
+
if (event.kind === 'session_boundary' && event.phase === 'reset') {
|
|
128
|
+
// Replace the map in place so existing Storage / Bucket / File
|
|
129
|
+
// handles keep working but observe an empty state.
|
|
130
|
+
const existing = SANDBOX_STATE.get(sandbox);
|
|
131
|
+
if (existing)
|
|
132
|
+
existing.clear();
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
return map;
|
|
137
|
+
}
|
|
138
|
+
function getSandboxStorage(app) {
|
|
139
|
+
const sandbox = app.sandbox;
|
|
140
|
+
const buckets = ensureBucketMap(sandbox);
|
|
141
|
+
return new SandboxStorage(buckets);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Sandbox `Storage` implementation. Holds a reference to the per-
|
|
145
|
+
* sandbox bucket map; each `bucket()` call returns a fresh `Bucket`
|
|
146
|
+
* handle bound to the same underlying map, mirroring how
|
|
147
|
+
* `@google-cloud/storage` returns lightweight per-call handles.
|
|
148
|
+
*/
|
|
149
|
+
class SandboxStorage {
|
|
150
|
+
buckets;
|
|
151
|
+
constructor(buckets) {
|
|
152
|
+
this.buckets = buckets;
|
|
153
|
+
}
|
|
154
|
+
bucket(name) {
|
|
155
|
+
const bucketName = name ?? DEFAULT_SANDBOX_BUCKET;
|
|
156
|
+
let files = this.buckets.get(bucketName);
|
|
157
|
+
if (!files) {
|
|
158
|
+
files = new Map();
|
|
159
|
+
this.buckets.set(bucketName, files);
|
|
160
|
+
}
|
|
161
|
+
return new SandboxBucket(bucketName, files);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
class SandboxBucket {
|
|
165
|
+
name;
|
|
166
|
+
files;
|
|
167
|
+
constructor(name, files) {
|
|
168
|
+
this.name = name;
|
|
169
|
+
this.files = files;
|
|
170
|
+
}
|
|
171
|
+
file(path) {
|
|
172
|
+
return new SandboxFile(path, this, this.files);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
class SandboxFile {
|
|
176
|
+
name;
|
|
177
|
+
bucket;
|
|
178
|
+
files;
|
|
179
|
+
constructor(name, bucket, files) {
|
|
180
|
+
this.name = name;
|
|
181
|
+
this.bucket = bucket;
|
|
182
|
+
this.files = files;
|
|
183
|
+
}
|
|
184
|
+
async save(data, options = {}) {
|
|
185
|
+
if (options.resumable === true) {
|
|
186
|
+
throw new Error('not implemented in pyric-admin/storage sandbox backend: resumable uploads');
|
|
187
|
+
}
|
|
188
|
+
const bytes = toBytes(data);
|
|
189
|
+
const metadata = options.metadata ?? {};
|
|
190
|
+
const entry = {
|
|
191
|
+
data: bytes,
|
|
192
|
+
metadata,
|
|
193
|
+
...(options.contentType !== undefined ? { contentType: options.contentType } : {}),
|
|
194
|
+
};
|
|
195
|
+
this.files.set(this.name, entry);
|
|
196
|
+
}
|
|
197
|
+
async download(_options = {}) {
|
|
198
|
+
const entry = this.files.get(this.name);
|
|
199
|
+
if (!entry) {
|
|
200
|
+
// Mirror the gcs/firebase-admin error message shape so consumer
|
|
201
|
+
// catch-blocks that string-match `No such object` keep working.
|
|
202
|
+
throw new Error(`No such object: ${this.bucket.name}/${this.name}`);
|
|
203
|
+
}
|
|
204
|
+
return [Buffer.from(entry.data)];
|
|
205
|
+
}
|
|
206
|
+
async delete() {
|
|
207
|
+
this.files.delete(this.name);
|
|
208
|
+
}
|
|
209
|
+
async exists() {
|
|
210
|
+
return [this.files.has(this.name)];
|
|
211
|
+
}
|
|
212
|
+
async getSignedUrl(options) {
|
|
213
|
+
return [stubSignedUrl(this.bucket.name, this.name, options)];
|
|
214
|
+
}
|
|
215
|
+
// ─── Deferred surface (declared so TS callers see a clear error) ────
|
|
216
|
+
/** @deprecated Streaming writes are deferred — see module header. */
|
|
217
|
+
createWriteStream() {
|
|
218
|
+
throw new Error('not implemented in pyric-admin/storage sandbox backend: createWriteStream');
|
|
219
|
+
}
|
|
220
|
+
/** @deprecated Streaming reads are deferred — see module header. */
|
|
221
|
+
createReadStream() {
|
|
222
|
+
throw new Error('not implemented in pyric-admin/storage sandbox backend: createReadStream');
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// ─── Remote sandbox arm (remote sandbox, slice 2) ───────────────────────
|
|
226
|
+
//
|
|
227
|
+
// The app's `Sandbox` is a Node-side handle onto the browser-hosted
|
|
228
|
+
// SharedWorker sandbox. Every data operation relays over the handle's
|
|
229
|
+
// worker channel with `actAs: { mode: 'admin' }` pinned — firebase-admin's
|
|
230
|
+
// rules-bypass semantics against the ONE object store the app + Studio +
|
|
231
|
+
// agents share (the host resolves the lens to `pyric/storage/internal`'s
|
|
232
|
+
// admin plane). There is deliberately NO local state here: a `WeakMap`
|
|
233
|
+
// bucket map keyed off a remote handle would be private server-side data
|
|
234
|
+
// the browser never sees, and the local arm's `onEvent` reset hook throws
|
|
235
|
+
// on remote handles by design.
|
|
236
|
+
//
|
|
237
|
+
// Divergences from the local arm, all LOUD:
|
|
238
|
+
// - single bucket: the worker's `pyric/storage` store is single-bucket
|
|
239
|
+
// ("the data store is shared" — bucket names only round-trip in
|
|
240
|
+
// metadata), so `bucket('non-default')` throws instead of silently
|
|
241
|
+
// merging buckets. The default bucket name matches the local arm.
|
|
242
|
+
// - byte payloads are capped at 8 MiB per op (whole-object buffering
|
|
243
|
+
// over four relay hops; streaming stays unsupported on both arms).
|
|
244
|
+
// `getSignedUrl` does NOT relay: it stays the byte-identical local stub.
|
|
245
|
+
/** firebase-admin's rules-bypass lens, pinned on every relayed operation. */
|
|
246
|
+
const STORAGE_REMOTE_ADMIN_LENS = { mode: 'admin' };
|
|
247
|
+
/**
|
|
248
|
+
* Raw per-op byte cap for relayed storage payloads. MUST mirror
|
|
249
|
+
* `pyric-tools`' `MAX_STORAGE_OP_BYTES` (serve/worker/protocol.ts) — the
|
|
250
|
+
* worker host enforces the same cap on its end. Inlined (like the RTDB
|
|
251
|
+
* push-id generator) because `pyric-admin` deliberately does not depend on
|
|
252
|
+
* `pyric-tools`.
|
|
253
|
+
*/
|
|
254
|
+
const MAX_REMOTE_STORAGE_OP_BYTES = 8 * 1024 * 1024;
|
|
255
|
+
/** One remote `Storage` per remote handle (handles only — never data). */
|
|
256
|
+
const remoteStorageBySandbox = new WeakMap();
|
|
257
|
+
function getRemoteStorage(sandbox) {
|
|
258
|
+
let storage = remoteStorageBySandbox.get(sandbox);
|
|
259
|
+
if (!storage) {
|
|
260
|
+
storage = new RemoteStorage(sandbox.channel);
|
|
261
|
+
remoteStorageBySandbox.set(sandbox, storage);
|
|
262
|
+
}
|
|
263
|
+
return storage;
|
|
264
|
+
}
|
|
265
|
+
class RemoteStorage {
|
|
266
|
+
channel;
|
|
267
|
+
constructor(channel) {
|
|
268
|
+
this.channel = channel;
|
|
269
|
+
}
|
|
270
|
+
bucket(name) {
|
|
271
|
+
// The worker's object store is single-bucket. A non-default name can't
|
|
272
|
+
// be faithfully relayed — throw loudly instead of silently merging
|
|
273
|
+
// buckets (the local arm has REAL multi-bucket isolation; this is the
|
|
274
|
+
// sharpest local/remote divergence, so it must be explicit).
|
|
275
|
+
if (name !== undefined && name !== DEFAULT_SANDBOX_BUCKET) {
|
|
276
|
+
throw new Error(`pyric-admin/storage: the remote (browser) sandbox has a single bucket — ` +
|
|
277
|
+
`bucket('${name}') cannot be isolated. Use bucket() (the default ` +
|
|
278
|
+
`'${DEFAULT_SANDBOX_BUCKET}' bucket) instead.`);
|
|
279
|
+
}
|
|
280
|
+
return new RemoteBucket(DEFAULT_SANDBOX_BUCKET, this.channel);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
class RemoteBucket {
|
|
284
|
+
name;
|
|
285
|
+
channel;
|
|
286
|
+
constructor(name, channel) {
|
|
287
|
+
this.name = name;
|
|
288
|
+
this.channel = channel;
|
|
289
|
+
}
|
|
290
|
+
file(path) {
|
|
291
|
+
return new RemoteFile(path, this, this.channel);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
class RemoteFile {
|
|
295
|
+
name;
|
|
296
|
+
bucket;
|
|
297
|
+
channel;
|
|
298
|
+
constructor(name, bucket, channel) {
|
|
299
|
+
this.name = name;
|
|
300
|
+
this.bucket = bucket;
|
|
301
|
+
this.channel = channel;
|
|
302
|
+
}
|
|
303
|
+
async save(data, options = {}) {
|
|
304
|
+
if (options.resumable === true) {
|
|
305
|
+
throw new Error('not implemented in pyric-admin/storage remote sandbox backend: resumable uploads');
|
|
306
|
+
}
|
|
307
|
+
const bytes = toBytes(data);
|
|
308
|
+
if (bytes.byteLength > MAX_REMOTE_STORAGE_OP_BYTES) {
|
|
309
|
+
throw payloadTooLarge(bytes.byteLength, `save() payload for '${this.name}'`);
|
|
310
|
+
}
|
|
311
|
+
await this.channel.op({
|
|
312
|
+
method: 'storage.putBytes',
|
|
313
|
+
path: this.name,
|
|
314
|
+
dataB64: Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString('base64'),
|
|
315
|
+
...(options.contentType !== undefined ? { contentType: options.contentType } : {}),
|
|
316
|
+
...(options.metadata !== undefined ? { metadata: options.metadata } : {}),
|
|
317
|
+
actAs: STORAGE_REMOTE_ADMIN_LENS,
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
async download(_options = {}) {
|
|
321
|
+
let wire;
|
|
322
|
+
try {
|
|
323
|
+
wire = (await this.channel.op({
|
|
324
|
+
method: 'storage.getBytes',
|
|
325
|
+
path: this.name,
|
|
326
|
+
actAs: STORAGE_REMOTE_ADMIN_LENS,
|
|
327
|
+
}));
|
|
328
|
+
}
|
|
329
|
+
catch (err) {
|
|
330
|
+
if (isObjectNotFound(err)) {
|
|
331
|
+
// Mirror the gcs/firebase-admin (and local arm) message shape so
|
|
332
|
+
// consumer catch-blocks that string-match `No such object` work
|
|
333
|
+
// identically across arms.
|
|
334
|
+
throw new Error(`No such object: ${this.bucket.name}/${this.name}`);
|
|
335
|
+
}
|
|
336
|
+
throw err;
|
|
337
|
+
}
|
|
338
|
+
return [Buffer.from(wire.dataB64, 'base64')];
|
|
339
|
+
}
|
|
340
|
+
async delete() {
|
|
341
|
+
try {
|
|
342
|
+
await this.channel.op({
|
|
343
|
+
method: 'storage.deleteObject',
|
|
344
|
+
path: this.name,
|
|
345
|
+
actAs: STORAGE_REMOTE_ADMIN_LENS,
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
catch (err) {
|
|
349
|
+
// The worker store's delete is already idempotent, but swallow a
|
|
350
|
+
// not-found defensively so the local arm's idempotent-delete contract
|
|
351
|
+
// holds even if `pyric/storage` adopts the strict prod throw later.
|
|
352
|
+
if (isObjectNotFound(err))
|
|
353
|
+
return;
|
|
354
|
+
throw err;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
async exists() {
|
|
358
|
+
try {
|
|
359
|
+
await this.channel.op({
|
|
360
|
+
method: 'storage.getMetadata',
|
|
361
|
+
path: this.name,
|
|
362
|
+
actAs: STORAGE_REMOTE_ADMIN_LENS,
|
|
363
|
+
});
|
|
364
|
+
return [true];
|
|
365
|
+
}
|
|
366
|
+
catch (err) {
|
|
367
|
+
if (isObjectNotFound(err))
|
|
368
|
+
return [false];
|
|
369
|
+
throw err;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
/** Local stub — byte-identical to the local arm's (no data needed, so it
|
|
373
|
+
* never relays). The sandbox does NOT serve the URL. */
|
|
374
|
+
async getSignedUrl(options) {
|
|
375
|
+
return [stubSignedUrl(this.bucket.name, this.name, options)];
|
|
376
|
+
}
|
|
377
|
+
// ─── Deferred surface (remediating throws, remote-flavored) ─────────
|
|
378
|
+
createWriteStream() {
|
|
379
|
+
throw new Error('not implemented in pyric-admin/storage remote sandbox backend: createWriteStream — ' +
|
|
380
|
+
'streams cannot span the bridge relay; use file.save(buffer) (≤ 8 MiB) instead.');
|
|
381
|
+
}
|
|
382
|
+
createReadStream() {
|
|
383
|
+
throw new Error('not implemented in pyric-admin/storage remote sandbox backend: createReadStream — ' +
|
|
384
|
+
'streams cannot span the bridge relay; use file.download() (≤ 8 MiB) instead.');
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
/** Is this relayed error the worker's `storage/object-not-found`? */
|
|
388
|
+
function isObjectNotFound(err) {
|
|
389
|
+
return err?.code === 'storage/object-not-found';
|
|
390
|
+
}
|
|
391
|
+
/** Over-cap rejection (code `payload-too-large`) — mirrors the worker host's
|
|
392
|
+
* message shape and names the streaming gap. */
|
|
393
|
+
function payloadTooLarge(sizeBytes, what) {
|
|
394
|
+
const err = new Error(`pyric-admin/storage: ${what} is ${sizeBytes} bytes — over the ` +
|
|
395
|
+
`${MAX_REMOTE_STORAGE_OP_BYTES / (1024 * 1024)} MiB remote storage op cap. ` +
|
|
396
|
+
'Streaming/resumable transfers are not supported on the sandbox backend; ' +
|
|
397
|
+
'split the object or keep it under the cap.');
|
|
398
|
+
err.code = 'payload-too-large';
|
|
399
|
+
return err;
|
|
400
|
+
}
|
|
401
|
+
// ─── Helpers ────────────────────────────────────────────────────────────
|
|
402
|
+
/**
|
|
403
|
+
* The deterministic sandbox signed-URL stub, shared by the local and remote
|
|
404
|
+
* arms so their output is byte-identical (the URL is never served — it's a
|
|
405
|
+
* stable placeholder for logs/fixtures/replay).
|
|
406
|
+
*/
|
|
407
|
+
function stubSignedUrl(bucketName, path, options) {
|
|
408
|
+
const expiresMs = normalizeExpires(options.expires);
|
|
409
|
+
return `pyric-sandbox-storage://${bucketName}/${path}?expires=${expiresMs}&action=${options.action}`;
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Normalize `Buffer | string | Uint8Array` into a fresh `Uint8Array`.
|
|
413
|
+
* We copy on ingest so callers can mutate their input buffer without
|
|
414
|
+
* corrupting stored state — mirrors how `firebase-admin/storage` /
|
|
415
|
+
* `@google-cloud/storage` treat `save` inputs.
|
|
416
|
+
*/
|
|
417
|
+
function toBytes(data) {
|
|
418
|
+
if (typeof data === 'string') {
|
|
419
|
+
return new TextEncoder().encode(data);
|
|
420
|
+
}
|
|
421
|
+
// Both Buffer (Node) and Uint8Array land here — copy into a new
|
|
422
|
+
// Uint8Array so the stored bytes are independent of the caller's
|
|
423
|
+
// reference. `slice()` produces a copy in both cases.
|
|
424
|
+
return new Uint8Array(data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength));
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Normalize the `expires` field into ms-since-epoch. Mirrors the
|
|
428
|
+
* accepted shapes from `@google-cloud/storage`'s `GetSignedUrlOptions`.
|
|
429
|
+
* The sandbox doesn't enforce expiration — the value is only embedded
|
|
430
|
+
* in the stub URL so consumers can round-trip it.
|
|
431
|
+
*/
|
|
432
|
+
function normalizeExpires(expires) {
|
|
433
|
+
if (typeof expires === 'number')
|
|
434
|
+
return expires;
|
|
435
|
+
if (expires instanceof Date)
|
|
436
|
+
return expires.getTime();
|
|
437
|
+
// String form — accept anything `Date` parses. Bogus input becomes
|
|
438
|
+
// `NaN`, which is still embeddable in the URL; we don't enforce
|
|
439
|
+
// strictness because the prod path delegates this to GCS anyway.
|
|
440
|
+
return new Date(expires).getTime();
|
|
441
|
+
}
|
|
442
|
+
//# 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,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pyric-admin",
|
|
3
|
+
"version": "0.1.0-alpha.7",
|
|
4
|
+
"description": "Pyric admin-shape adapters (firestore, auth, database, storage) with swappable sandbox/prod backends. Mirrors firebase-admin.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
"./app": {
|
|
8
|
+
"types": "./dist/app/index.d.ts",
|
|
9
|
+
"import": "./dist/app/index.js"
|
|
10
|
+
},
|
|
11
|
+
"./firestore": {
|
|
12
|
+
"types": "./dist/firestore/index.d.ts",
|
|
13
|
+
"import": "./dist/firestore/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./auth": {
|
|
16
|
+
"types": "./dist/auth/index.d.ts",
|
|
17
|
+
"import": "./dist/auth/index.js"
|
|
18
|
+
},
|
|
19
|
+
"./database": {
|
|
20
|
+
"types": "./dist/database/index.d.ts",
|
|
21
|
+
"import": "./dist/database/index.js"
|
|
22
|
+
},
|
|
23
|
+
"./storage": {
|
|
24
|
+
"types": "./dist/storage/index.d.ts",
|
|
25
|
+
"import": "./dist/storage/index.js"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"README.md"
|
|
31
|
+
],
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsc",
|
|
34
|
+
"test": "bun test",
|
|
35
|
+
"typecheck": "bun x tsc -p tsconfig.json --noEmit"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"pyric": "^0.1.0-alpha.7",
|
|
39
|
+
"firebase-admin": "^13.0.0"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/bun": "latest",
|
|
43
|
+
"typescript": "^5.7.0",
|
|
44
|
+
"fake-indexeddb": "^6.0.0"
|
|
45
|
+
},
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=22"
|
|
48
|
+
},
|
|
49
|
+
"publishConfig": {
|
|
50
|
+
"access": "public"
|
|
51
|
+
}
|
|
52
|
+
}
|