pyric-tools 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 +125 -0
- package/dist/auth/domains/handler.d.ts +6 -0
- package/dist/auth/domains/handler.d.ts.map +1 -0
- package/dist/auth/domains/handler.js +75 -0
- package/dist/auth/domains/handler.js.map +1 -0
- package/dist/auth/domains/spec.d.ts +25 -0
- package/dist/auth/domains/spec.d.ts.map +1 -0
- package/dist/auth/domains/spec.js +6 -0
- package/dist/auth/domains/spec.js.map +1 -0
- package/dist/auth/index.d.ts +34 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +30 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/mapper.d.ts +5 -0
- package/dist/auth/mapper.d.ts.map +1 -0
- package/dist/auth/mapper.js +49 -0
- package/dist/auth/mapper.js.map +1 -0
- package/dist/auth/provider/handler.d.ts +9 -0
- package/dist/auth/provider/handler.d.ts.map +1 -0
- package/dist/auth/provider/handler.js +128 -0
- package/dist/auth/provider/handler.js.map +1 -0
- package/dist/auth/provider/spec.d.ts +29 -0
- package/dist/auth/provider/spec.d.ts.map +1 -0
- package/dist/auth/provider/spec.js +12 -0
- package/dist/auth/provider/spec.js.map +1 -0
- package/dist/auth/resolver.d.ts +16 -0
- package/dist/auth/resolver.d.ts.map +1 -0
- package/dist/auth/resolver.js +32 -0
- package/dist/auth/resolver.js.map +1 -0
- package/dist/auth/tools.d.ts +23 -0
- package/dist/auth/tools.d.ts.map +1 -0
- package/dist/auth/tools.js +71 -0
- package/dist/auth/tools.js.map +1 -0
- package/dist/auth/types.d.ts +37 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +17 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/bridge/client/bridge.d.ts +133 -0
- package/dist/bridge/client/bridge.d.ts.map +1 -0
- package/dist/bridge/client/bridge.js +430 -0
- package/dist/bridge/client/bridge.js.map +1 -0
- package/dist/bridge/client/dispatch.d.ts +49 -0
- package/dist/bridge/client/dispatch.d.ts.map +1 -0
- package/dist/bridge/client/dispatch.js +103 -0
- package/dist/bridge/client/dispatch.js.map +1 -0
- package/dist/bridge/client.d.ts +24 -0
- package/dist/bridge/client.d.ts.map +1 -0
- package/dist/bridge/client.js +26 -0
- package/dist/bridge/client.js.map +1 -0
- package/dist/bridge/protocol.d.ts +228 -0
- package/dist/bridge/protocol.d.ts.map +1 -0
- package/dist/bridge/protocol.js +131 -0
- package/dist/bridge/protocol.js.map +1 -0
- package/dist/bridge/server/audit.d.ts +19 -0
- package/dist/bridge/server/audit.d.ts.map +1 -0
- package/dist/bridge/server/audit.js +46 -0
- package/dist/bridge/server/audit.js.map +1 -0
- package/dist/bridge/server/bridge.d.ts +165 -0
- package/dist/bridge/server/bridge.d.ts.map +1 -0
- package/dist/bridge/server/bridge.js +410 -0
- package/dist/bridge/server/bridge.js.map +1 -0
- package/dist/bridge/server/confirm-policy.d.ts +56 -0
- package/dist/bridge/server/confirm-policy.d.ts.map +1 -0
- package/dist/bridge/server/confirm-policy.js +107 -0
- package/dist/bridge/server/confirm-policy.js.map +1 -0
- package/dist/bridge/server/confirm-prompt.d.ts +73 -0
- package/dist/bridge/server/confirm-prompt.d.ts.map +1 -0
- package/dist/bridge/server/confirm-prompt.js +199 -0
- package/dist/bridge/server/confirm-prompt.js.map +1 -0
- package/dist/bridge/server/confirm.d.ts +92 -0
- package/dist/bridge/server/confirm.d.ts.map +1 -0
- package/dist/bridge/server/confirm.js +210 -0
- package/dist/bridge/server/confirm.js.map +1 -0
- package/dist/bridge/server/headless.d.ts +36 -0
- package/dist/bridge/server/headless.d.ts.map +1 -0
- package/dist/bridge/server/headless.js +132 -0
- package/dist/bridge/server/headless.js.map +1 -0
- package/dist/bridge/server/json-schema-to-zod.d.ts +37 -0
- package/dist/bridge/server/json-schema-to-zod.d.ts.map +1 -0
- package/dist/bridge/server/json-schema-to-zod.js +93 -0
- package/dist/bridge/server/json-schema-to-zod.js.map +1 -0
- package/dist/bridge/server/local-bridge.d.ts +33 -0
- package/dist/bridge/server/local-bridge.d.ts.map +1 -0
- package/dist/bridge/server/local-bridge.js +42 -0
- package/dist/bridge/server/local-bridge.js.map +1 -0
- package/dist/bridge/server/logger.d.ts +28 -0
- package/dist/bridge/server/logger.d.ts.map +1 -0
- package/dist/bridge/server/logger.js +42 -0
- package/dist/bridge/server/logger.js.map +1 -0
- package/dist/bridge/server/mcp.d.ts +33 -0
- package/dist/bridge/server/mcp.d.ts.map +1 -0
- package/dist/bridge/server/mcp.js +159 -0
- package/dist/bridge/server/mcp.js.map +1 -0
- package/dist/bridge/server/peer.d.ts +39 -0
- package/dist/bridge/server/peer.d.ts.map +1 -0
- package/dist/bridge/server/peer.js +189 -0
- package/dist/bridge/server/peer.js.map +1 -0
- package/dist/bridge/server/standalone.d.ts +102 -0
- package/dist/bridge/server/standalone.d.ts.map +1 -0
- package/dist/bridge/server/standalone.js +352 -0
- package/dist/bridge/server/standalone.js.map +1 -0
- package/dist/bridge/server/tool-metadata.d.ts +38 -0
- package/dist/bridge/server/tool-metadata.d.ts.map +1 -0
- package/dist/bridge/server/tool-metadata.js +79 -0
- package/dist/bridge/server/tool-metadata.js.map +1 -0
- package/dist/bridge/server.d.ts +25 -0
- package/dist/bridge/server.d.ts.map +1 -0
- package/dist/bridge/server.js +23 -0
- package/dist/bridge/server.js.map +1 -0
- package/dist/cli/auth.d.ts +37 -0
- package/dist/cli/auth.d.ts.map +1 -0
- package/dist/cli/auth.js +119 -0
- package/dist/cli/auth.js.map +1 -0
- package/dist/cli/database-rules.d.ts +25 -0
- package/dist/cli/database-rules.d.ts.map +1 -0
- package/dist/cli/database-rules.js +215 -0
- package/dist/cli/database-rules.js.map +1 -0
- package/dist/cli/deploy-progress.d.ts +35 -0
- package/dist/cli/deploy-progress.d.ts.map +1 -0
- package/dist/cli/deploy-progress.js +69 -0
- package/dist/cli/deploy-progress.js.map +1 -0
- package/dist/cli/deploy.d.ts +81 -0
- package/dist/cli/deploy.d.ts.map +1 -0
- package/dist/cli/deploy.js +413 -0
- package/dist/cli/deploy.js.map +1 -0
- package/dist/cli/dev-runner.d.ts +112 -0
- package/dist/cli/dev-runner.d.ts.map +1 -0
- package/dist/cli/dev-runner.js +227 -0
- package/dist/cli/dev-runner.js.map +1 -0
- package/dist/cli/discover.d.ts +47 -0
- package/dist/cli/discover.d.ts.map +1 -0
- package/dist/cli/discover.js +77 -0
- package/dist/cli/discover.js.map +1 -0
- package/dist/cli/firebase-json.d.ts +66 -0
- package/dist/cli/firebase-json.d.ts.map +1 -0
- package/dist/cli/firebase-json.js +60 -0
- package/dist/cli/firebase-json.js.map +1 -0
- package/dist/cli/index.d.ts +55 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +500 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init-templates.d.ts +37 -0
- package/dist/cli/init-templates.d.ts.map +1 -0
- package/dist/cli/init-templates.js +638 -0
- package/dist/cli/init-templates.js.map +1 -0
- package/dist/cli/init.d.ts +124 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +423 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/login.d.ts +18 -0
- package/dist/cli/login.d.ts.map +1 -0
- package/dist/cli/login.js +59 -0
- package/dist/cli/login.js.map +1 -0
- package/dist/cli/mcp-proxy.d.ts +10 -0
- package/dist/cli/mcp-proxy.d.ts.map +1 -0
- package/dist/cli/mcp-proxy.js +126 -0
- package/dist/cli/mcp-proxy.js.map +1 -0
- package/dist/cli/parse-args.d.ts +20 -0
- package/dist/cli/parse-args.d.ts.map +1 -0
- package/dist/cli/parse-args.js +69 -0
- package/dist/cli/parse-args.js.map +1 -0
- package/dist/cli/rules.d.ts +40 -0
- package/dist/cli/rules.d.ts.map +1 -0
- package/dist/cli/rules.js +162 -0
- package/dist/cli/rules.js.map +1 -0
- package/dist/cli/scope.d.ts +38 -0
- package/dist/cli/scope.d.ts.map +1 -0
- package/dist/cli/scope.js +63 -0
- package/dist/cli/scope.js.map +1 -0
- package/dist/cli/serve.d.ts +122 -0
- package/dist/cli/serve.d.ts.map +1 -0
- package/dist/cli/serve.js +685 -0
- package/dist/cli/serve.js.map +1 -0
- package/dist/cli/snapshot.d.ts +22 -0
- package/dist/cli/snapshot.d.ts.map +1 -0
- package/dist/cli/snapshot.js +139 -0
- package/dist/cli/snapshot.js.map +1 -0
- package/dist/cli/verify.d.ts +23 -0
- package/dist/cli/verify.d.ts.map +1 -0
- package/dist/cli/verify.js +349 -0
- package/dist/cli/verify.js.map +1 -0
- package/dist/credentials/core/authorize.d.ts +22 -0
- package/dist/credentials/core/authorize.d.ts.map +1 -0
- package/dist/credentials/core/authorize.js +39 -0
- package/dist/credentials/core/authorize.js.map +1 -0
- package/dist/credentials/core/client.d.ts +14 -0
- package/dist/credentials/core/client.d.ts.map +1 -0
- package/dist/credentials/core/client.js +13 -0
- package/dist/credentials/core/client.js.map +1 -0
- package/dist/credentials/core/exchange.d.ts +24 -0
- package/dist/credentials/core/exchange.d.ts.map +1 -0
- package/dist/credentials/core/exchange.js +46 -0
- package/dist/credentials/core/exchange.js.map +1 -0
- package/dist/credentials/core/flow.d.ts +15 -0
- package/dist/credentials/core/flow.d.ts.map +1 -0
- package/dist/credentials/core/flow.js +40 -0
- package/dist/credentials/core/flow.js.map +1 -0
- package/dist/credentials/core/from-user-credential.d.ts +3 -0
- package/dist/credentials/core/from-user-credential.d.ts.map +1 -0
- package/dist/credentials/core/from-user-credential.js +19 -0
- package/dist/credentials/core/from-user-credential.js.map +1 -0
- package/dist/credentials/core/scopes.d.ts +26 -0
- package/dist/credentials/core/scopes.d.ts.map +1 -0
- package/dist/credentials/core/scopes.js +32 -0
- package/dist/credentials/core/scopes.js.map +1 -0
- package/dist/credentials/core/types.d.ts +72 -0
- package/dist/credentials/core/types.d.ts.map +1 -0
- package/dist/credentials/core/types.js +2 -0
- package/dist/credentials/core/types.js.map +1 -0
- package/dist/credentials/index.d.ts +14 -0
- package/dist/credentials/index.d.ts.map +1 -0
- package/dist/credentials/index.js +13 -0
- package/dist/credentials/index.js.map +1 -0
- package/dist/credentials/node/ensure-scope.d.ts +29 -0
- package/dist/credentials/node/ensure-scope.d.ts.map +1 -0
- package/dist/credentials/node/ensure-scope.js +42 -0
- package/dist/credentials/node/ensure-scope.js.map +1 -0
- package/dist/credentials/node/file-store.d.ts +4 -0
- package/dist/credentials/node/file-store.d.ts.map +1 -0
- package/dist/credentials/node/file-store.js +52 -0
- package/dist/credentials/node/file-store.js.map +1 -0
- package/dist/credentials/node/from-adc.d.ts +10 -0
- package/dist/credentials/node/from-adc.d.ts.map +1 -0
- package/dist/credentials/node/from-adc.js +60 -0
- package/dist/credentials/node/from-adc.js.map +1 -0
- package/dist/credentials/node/index.d.ts +10 -0
- package/dist/credentials/node/index.d.ts.map +1 -0
- package/dist/credentials/node/index.js +10 -0
- package/dist/credentials/node/index.js.map +1 -0
- package/dist/credentials/node/loopback-authorizer.d.ts +12 -0
- package/dist/credentials/node/loopback-authorizer.d.ts.map +1 -0
- package/dist/credentials/node/loopback-authorizer.js +61 -0
- package/dist/credentials/node/loopback-authorizer.js.map +1 -0
- package/dist/credentials/node/resolve-local-token.d.ts +20 -0
- package/dist/credentials/node/resolve-local-token.d.ts.map +1 -0
- package/dist/credentials/node/resolve-local-token.js +97 -0
- package/dist/credentials/node/resolve-local-token.js.map +1 -0
- package/dist/credentials/server/bff.d.ts +44 -0
- package/dist/credentials/server/bff.d.ts.map +1 -0
- package/dist/credentials/server/bff.js +43 -0
- package/dist/credentials/server/bff.js.map +1 -0
- package/dist/deploy/api-enablement.d.ts +45 -0
- package/dist/deploy/api-enablement.d.ts.map +1 -0
- package/dist/deploy/api-enablement.js +125 -0
- package/dist/deploy/api-enablement.js.map +1 -0
- package/dist/deploy/firestore/databases.d.ts +41 -0
- package/dist/deploy/firestore/databases.d.ts.map +1 -0
- package/dist/deploy/firestore/databases.js +63 -0
- package/dist/deploy/firestore/databases.js.map +1 -0
- package/dist/deploy/firestore/indexes.d.ts +120 -0
- package/dist/deploy/firestore/indexes.d.ts.map +1 -0
- package/dist/deploy/firestore/indexes.js +243 -0
- package/dist/deploy/firestore/indexes.js.map +1 -0
- package/dist/deploy/firestore/recipes.d.ts +21 -0
- package/dist/deploy/firestore/recipes.d.ts.map +1 -0
- package/dist/deploy/firestore/recipes.js +34 -0
- package/dist/deploy/firestore/recipes.js.map +1 -0
- package/dist/deploy/firestore/rules.d.ts +76 -0
- package/dist/deploy/firestore/rules.d.ts.map +1 -0
- package/dist/deploy/firestore/rules.js +180 -0
- package/dist/deploy/firestore/rules.js.map +1 -0
- package/dist/deploy/from-admin-app.d.ts +20 -0
- package/dist/deploy/from-admin-app.d.ts.map +1 -0
- package/dist/deploy/from-admin-app.js +18 -0
- package/dist/deploy/from-admin-app.js.map +1 -0
- package/dist/deploy/from-service-account.d.ts +29 -0
- package/dist/deploy/from-service-account.d.ts.map +1 -0
- package/dist/deploy/from-service-account.js +115 -0
- package/dist/deploy/from-service-account.js.map +1 -0
- package/dist/deploy/functions/bundle.d.ts +37 -0
- package/dist/deploy/functions/bundle.d.ts.map +1 -0
- package/dist/deploy/functions/bundle.js +181 -0
- package/dist/deploy/functions/bundle.js.map +1 -0
- package/dist/deploy/functions/core.d.ts +18 -0
- package/dist/deploy/functions/core.d.ts.map +1 -0
- package/dist/deploy/functions/core.js +211 -0
- package/dist/deploy/functions/core.js.map +1 -0
- package/dist/deploy/functions/iam.d.ts +17 -0
- package/dist/deploy/functions/iam.d.ts.map +1 -0
- package/dist/deploy/functions/iam.js +40 -0
- package/dist/deploy/functions/iam.js.map +1 -0
- package/dist/deploy/functions/operation.d.ts +39 -0
- package/dist/deploy/functions/operation.d.ts.map +1 -0
- package/dist/deploy/functions/operation.js +37 -0
- package/dist/deploy/functions/operation.js.map +1 -0
- package/dist/deploy/functions/spec.d.ts +69 -0
- package/dist/deploy/functions/spec.d.ts.map +1 -0
- package/dist/deploy/functions/spec.js +7 -0
- package/dist/deploy/functions/spec.js.map +1 -0
- package/dist/deploy/functions/types.d.ts +50 -0
- package/dist/deploy/functions/types.d.ts.map +1 -0
- package/dist/deploy/functions/types.js +3 -0
- package/dist/deploy/functions/types.js.map +1 -0
- package/dist/deploy/hosting/channels.d.ts +93 -0
- package/dist/deploy/hosting/channels.d.ts.map +1 -0
- package/dist/deploy/hosting/channels.js +134 -0
- package/dist/deploy/hosting/channels.js.map +1 -0
- package/dist/deploy/hosting/config.d.ts +28 -0
- package/dist/deploy/hosting/config.d.ts.map +1 -0
- package/dist/deploy/hosting/config.js +261 -0
- package/dist/deploy/hosting/config.js.map +1 -0
- package/dist/deploy/hosting/core.d.ts +38 -0
- package/dist/deploy/hosting/core.d.ts.map +1 -0
- package/dist/deploy/hosting/core.js +311 -0
- package/dist/deploy/hosting/core.js.map +1 -0
- package/dist/deploy/hosting/gzip.d.ts +11 -0
- package/dist/deploy/hosting/gzip.d.ts.map +1 -0
- package/dist/deploy/hosting/gzip.js +20 -0
- package/dist/deploy/hosting/gzip.js.map +1 -0
- package/dist/deploy/hosting/hash.d.ts +6 -0
- package/dist/deploy/hosting/hash.d.ts.map +1 -0
- package/dist/deploy/hosting/hash.js +17 -0
- package/dist/deploy/hosting/hash.js.map +1 -0
- package/dist/deploy/hosting/sites.d.ts +77 -0
- package/dist/deploy/hosting/sites.d.ts.map +1 -0
- package/dist/deploy/hosting/sites.js +73 -0
- package/dist/deploy/hosting/sites.js.map +1 -0
- package/dist/deploy/hosting/spec.d.ts +140 -0
- package/dist/deploy/hosting/spec.d.ts.map +1 -0
- package/dist/deploy/hosting/spec.js +8 -0
- package/dist/deploy/hosting/spec.js.map +1 -0
- package/dist/deploy/hosting/types.d.ts +71 -0
- package/dist/deploy/hosting/types.d.ts.map +1 -0
- package/dist/deploy/hosting/types.js +3 -0
- package/dist/deploy/hosting/types.js.map +1 -0
- package/dist/deploy/hosting/walk.d.ts +31 -0
- package/dist/deploy/hosting/walk.d.ts.map +1 -0
- package/dist/deploy/hosting/walk.js +167 -0
- package/dist/deploy/hosting/walk.js.map +1 -0
- package/dist/deploy/index.d.ts +51 -0
- package/dist/deploy/index.d.ts.map +1 -0
- package/dist/deploy/index.js +50 -0
- package/dist/deploy/index.js.map +1 -0
- package/dist/deploy/memoize-ttl.d.ts +58 -0
- package/dist/deploy/memoize-ttl.d.ts.map +1 -0
- package/dist/deploy/memoize-ttl.js +88 -0
- package/dist/deploy/memoize-ttl.js.map +1 -0
- package/dist/deploy/namespaces.d.ts +119 -0
- package/dist/deploy/namespaces.d.ts.map +1 -0
- package/dist/deploy/namespaces.js +192 -0
- package/dist/deploy/namespaces.js.map +1 -0
- package/dist/deploy/preflight.d.ts +119 -0
- package/dist/deploy/preflight.d.ts.map +1 -0
- package/dist/deploy/preflight.js +440 -0
- package/dist/deploy/preflight.js.map +1 -0
- package/dist/deploy/provider.d.ts +130 -0
- package/dist/deploy/provider.d.ts.map +1 -0
- package/dist/deploy/provider.js +21 -0
- package/dist/deploy/provider.js.map +1 -0
- package/dist/deploy/providers/database.d.ts +8 -0
- package/dist/deploy/providers/database.d.ts.map +1 -0
- package/dist/deploy/providers/database.js +37 -0
- package/dist/deploy/providers/database.js.map +1 -0
- package/dist/deploy/providers/firestore.d.ts +11 -0
- package/dist/deploy/providers/firestore.d.ts.map +1 -0
- package/dist/deploy/providers/firestore.js +43 -0
- package/dist/deploy/providers/firestore.js.map +1 -0
- package/dist/deploy/providers/functions.d.ts +9 -0
- package/dist/deploy/providers/functions.d.ts.map +1 -0
- package/dist/deploy/providers/functions.js +49 -0
- package/dist/deploy/providers/functions.js.map +1 -0
- package/dist/deploy/providers/hosting.d.ts +13 -0
- package/dist/deploy/providers/hosting.d.ts.map +1 -0
- package/dist/deploy/providers/hosting.js +149 -0
- package/dist/deploy/providers/hosting.js.map +1 -0
- package/dist/deploy/providers/storage.d.ts +9 -0
- package/dist/deploy/providers/storage.d.ts.map +1 -0
- package/dist/deploy/providers/storage.js +46 -0
- package/dist/deploy/providers/storage.js.map +1 -0
- package/dist/deploy/registry.d.ts +17 -0
- package/dist/deploy/registry.d.ts.map +1 -0
- package/dist/deploy/registry.js +15 -0
- package/dist/deploy/registry.js.map +1 -0
- package/dist/deploy/rtdb/rules.d.ts +21 -0
- package/dist/deploy/rtdb/rules.d.ts.map +1 -0
- package/dist/deploy/rtdb/rules.js +104 -0
- package/dist/deploy/rtdb/rules.js.map +1 -0
- package/dist/deploy/scope.d.ts +81 -0
- package/dist/deploy/scope.d.ts.map +1 -0
- package/dist/deploy/scope.js +44 -0
- package/dist/deploy/scope.js.map +1 -0
- package/dist/deploy/tools.d.ts +55 -0
- package/dist/deploy/tools.d.ts.map +1 -0
- package/dist/deploy/tools.js +329 -0
- package/dist/deploy/tools.js.map +1 -0
- package/dist/deploy/with-resolved-scope.d.ts +31 -0
- package/dist/deploy/with-resolved-scope.d.ts.map +1 -0
- package/dist/deploy/with-resolved-scope.js +73 -0
- package/dist/deploy/with-resolved-scope.js.map +1 -0
- package/dist/discover/concurrency.d.ts +42 -0
- package/dist/discover/concurrency.d.ts.map +1 -0
- package/dist/discover/concurrency.js +113 -0
- package/dist/discover/concurrency.js.map +1 -0
- package/dist/discover/crawler-adapter.d.ts +49 -0
- package/dist/discover/crawler-adapter.d.ts.map +1 -0
- package/dist/discover/crawler-adapter.js +92 -0
- package/dist/discover/crawler-adapter.js.map +1 -0
- package/dist/discover/crawler.d.ts +333 -0
- package/dist/discover/crawler.d.ts.map +1 -0
- package/dist/discover/crawler.js +764 -0
- package/dist/discover/crawler.js.map +1 -0
- package/dist/discover/findCollectionGroup.d.ts +80 -0
- package/dist/discover/findCollectionGroup.d.ts.map +1 -0
- package/dist/discover/findCollectionGroup.js +81 -0
- package/dist/discover/findCollectionGroup.js.map +1 -0
- package/dist/discover/index.d.ts +15 -0
- package/dist/discover/index.d.ts.map +1 -0
- package/dist/discover/index.js +24 -0
- package/dist/discover/index.js.map +1 -0
- package/dist/discover/merge.d.ts +108 -0
- package/dist/discover/merge.d.ts.map +1 -0
- package/dist/discover/merge.js +394 -0
- package/dist/discover/merge.js.map +1 -0
- package/dist/discover/rest-crawler-firestore.d.ts +51 -0
- package/dist/discover/rest-crawler-firestore.d.ts.map +1 -0
- package/dist/discover/rest-crawler-firestore.js +154 -0
- package/dist/discover/rest-crawler-firestore.js.map +1 -0
- package/dist/discover/session.d.ts +116 -0
- package/dist/discover/session.d.ts.map +1 -0
- package/dist/discover/session.js +331 -0
- package/dist/discover/session.js.map +1 -0
- package/dist/discover/tools.d.ts +59 -0
- package/dist/discover/tools.d.ts.map +1 -0
- package/dist/discover/tools.js +115 -0
- package/dist/discover/tools.js.map +1 -0
- package/dist/discover/types.d.ts +191 -0
- package/dist/discover/types.d.ts.map +1 -0
- package/dist/discover/types.js +12 -0
- package/dist/discover/types.js.map +1 -0
- package/dist/discover/wire.d.ts +81 -0
- package/dist/discover/wire.d.ts.map +1 -0
- package/dist/discover/wire.js +308 -0
- package/dist/discover/wire.js.map +1 -0
- package/dist/pkg-version.d.ts +2 -0
- package/dist/pkg-version.d.ts.map +1 -0
- package/dist/pkg-version.js +47 -0
- package/dist/pkg-version.js.map +1 -0
- package/dist/register/esm-exports.d.ts +26 -0
- package/dist/register/esm-exports.d.ts.map +1 -0
- package/dist/register/esm-exports.js +61 -0
- package/dist/register/esm-exports.js.map +1 -0
- package/dist/register/exempt.d.ts +11 -0
- package/dist/register/exempt.d.ts.map +1 -0
- package/dist/register/exempt.js +74 -0
- package/dist/register/exempt.js.map +1 -0
- package/dist/register/hooks.d.ts +13 -0
- package/dist/register/hooks.d.ts.map +1 -0
- package/dist/register/hooks.js +15 -0
- package/dist/register/hooks.js.map +1 -0
- package/dist/register/index.d.ts +5 -0
- package/dist/register/index.d.ts.map +1 -0
- package/dist/register/index.js +126 -0
- package/dist/register/index.js.map +1 -0
- package/dist/register/mapping.d.ts +17 -0
- package/dist/register/mapping.d.ts.map +1 -0
- package/dist/register/mapping.js +31 -0
- package/dist/register/mapping.js.map +1 -0
- package/dist/registry/admin-deps.d.ts +17 -0
- package/dist/registry/admin-deps.d.ts.map +1 -0
- package/dist/registry/admin-deps.js +68 -0
- package/dist/registry/admin-deps.js.map +1 -0
- package/dist/registry/compose.d.ts +68 -0
- package/dist/registry/compose.d.ts.map +1 -0
- package/dist/registry/compose.js +113 -0
- package/dist/registry/compose.js.map +1 -0
- package/dist/registry/index.d.ts +11 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +11 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/remote/index.d.ts +232 -0
- package/dist/remote/index.d.ts.map +1 -0
- package/dist/remote/index.js +719 -0
- package/dist/remote/index.js.map +1 -0
- package/dist/rtdb/rules-json.d.ts +8 -0
- package/dist/rtdb/rules-json.d.ts.map +1 -0
- package/dist/rtdb/rules-json.js +17 -0
- package/dist/rtdb/rules-json.js.map +1 -0
- package/dist/serve/bridge-mount.d.ts +38 -0
- package/dist/serve/bridge-mount.d.ts.map +1 -0
- package/dist/serve/bridge-mount.js +162 -0
- package/dist/serve/bridge-mount.js.map +1 -0
- package/dist/serve/bundler.d.ts +134 -0
- package/dist/serve/bundler.d.ts.map +1 -0
- package/dist/serve/bundler.js +452 -0
- package/dist/serve/bundler.js.map +1 -0
- package/dist/serve/capture-store.d.ts +27 -0
- package/dist/serve/capture-store.d.ts.map +1 -0
- package/dist/serve/capture-store.js +47 -0
- package/dist/serve/capture-store.js.map +1 -0
- package/dist/serve/discovery.d.ts +71 -0
- package/dist/serve/discovery.d.ts.map +1 -0
- package/dist/serve/discovery.js +158 -0
- package/dist/serve/discovery.js.map +1 -0
- package/dist/serve/docs-ui/_astro/_slug_.BsN3bPok.css +1 -0
- package/dist/serve/docs-ui/docs/_rhythm/index.html +99 -0
- package/dist/serve/docs-ui/docs/_rhythm.md +101 -0
- package/dist/serve/docs-ui/docs/index.html +1 -0
- package/dist/serve/docs-ui/docs/index.json +9914 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore/index.html +38 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-explanation-error-translation/index.html +57 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-explanation-error-translation.md +87 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-explanation-per-call-delegate/index.html +58 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-explanation-per-call-delegate.md +86 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-explanation-why-mirror-admin-shape/index.html +59 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-explanation-why-mirror-admin-shape.md +82 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-run-a-transaction/index.html +53 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-run-a-transaction.md +70 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-seed-and-set-rules/index.html +62 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-seed-and-set-rules.md +86 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-translate-denials/index.html +80 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-translate-denials.md +92 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-use-onsnapshot/index.html +57 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-use-onsnapshot.md +78 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-write-a-batch/index.html +50 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-write-a-batch.md +67 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-api/index.html +53 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-api.md +73 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-onsnapshot/index.html +68 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-onsnapshot.md +75 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-re-exported-types/index.html +76 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-re-exported-types.md +95 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-sandbox-firestore/index.html +40 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-sandbox-firestore.md +73 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-tutorials-01-first-admin-session/index.html +118 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-tutorials-01-first-admin-session.md +146 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore.md +49 -0
- package/dist/serve/docs-ui/docs/pyric-auth/index.html +64 -0
- package/dist/serve/docs-ui/docs/pyric-auth-compat/index.html +874 -0
- package/dist/serve/docs-ui/docs/pyric-auth-compat.md +265 -0
- package/dist/serve/docs-ui/docs/pyric-auth-reference-api/index.html +112 -0
- package/dist/serve/docs-ui/docs/pyric-auth-reference-api.md +129 -0
- package/dist/serve/docs-ui/docs/pyric-auth-reference-feature-matrix/index.html +781 -0
- package/dist/serve/docs-ui/docs/pyric-auth-reference-feature-matrix.md +198 -0
- package/dist/serve/docs-ui/docs/pyric-auth-reference-sandbox-test-driver/index.html +80 -0
- package/dist/serve/docs-ui/docs/pyric-auth-reference-sandbox-test-driver.md +107 -0
- package/dist/serve/docs-ui/docs/pyric-auth.md +84 -0
- package/dist/serve/docs-ui/docs/pyric-database/index.html +36 -0
- package/dist/serve/docs-ui/docs/pyric-database-compat/index.html +2428 -0
- package/dist/serve/docs-ui/docs/pyric-database-compat.md +850 -0
- package/dist/serve/docs-ui/docs/pyric-database-explanation-rules-authoring-and-deploy-are-separate/index.html +23 -0
- package/dist/serve/docs-ui/docs/pyric-database-explanation-rules-authoring-and-deploy-are-separate.md +29 -0
- package/dist/serve/docs-ui/docs/pyric-database-reference-rules-tooling/index.html +263 -0
- package/dist/serve/docs-ui/docs/pyric-database-reference-rules-tooling.md +288 -0
- package/dist/serve/docs-ui/docs/pyric-database-tutorials-01-author-rtdb-rules-with-constraints/index.html +116 -0
- package/dist/serve/docs-ui/docs/pyric-database-tutorials-01-author-rtdb-rules-with-constraints.md +142 -0
- package/dist/serve/docs-ui/docs/pyric-database.md +18 -0
- package/dist/serve/docs-ui/docs/pyric-firestore/index.html +54 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-compat/index.html +1345 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-compat.md +366 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-explanation-rules-tooling-is-separate/index.html +79 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-explanation-rules-tooling-is-separate.md +62 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-explanation-target-symbol-opacity/index.html +59 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-explanation-target-symbol-opacity.md +85 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-explanation-two-backends-one-surface/index.html +61 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-explanation-two-backends-one-surface.md +87 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-build-queries/index.html +105 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-build-queries.md +138 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-migrate-from-firebase-firestore/index.html +65 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-migrate-from-firebase-firestore.md +93 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-pick-a-backend/index.html +112 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-pick-a-backend.md +100 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-run-a-transaction/index.html +42 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-run-a-transaction.md +55 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-use-onsnapshot/index.html +61 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-use-onsnapshot.md +83 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-use-sandbox-ops/index.html +52 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-use-sandbox-ops.md +73 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-api/index.html +132 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-api.md +160 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-feature-matrix/index.html +793 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-feature-matrix.md +239 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-getfirestore/index.html +55 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-getfirestore.md +76 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-query-constraints/index.html +78 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-query-constraints.md +115 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-sandbox-ops/index.html +53 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-sandbox-ops.md +76 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-tool-factories/index.html +51 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-tool-factories.md +65 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-tutorials-01-write-a-sandbox-demo/index.html +127 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-tutorials-01-write-a-sandbox-demo.md +157 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-tutorials-02-swap-to-prod-backend/index.html +85 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-tutorials-02-swap-to-prod-backend.md +122 -0
- package/dist/serve/docs-ui/docs/pyric-firestore.md +69 -0
- package/dist/serve/docs-ui/docs/pyric-rules/index.html +93 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-agent-failure-modes/index.html +50 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-agent-failure-modes.md +74 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-lint-vs-validate-vs-simulate-vs-test/index.html +79 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-lint-vs-validate-vs-simulate-vs-test.md +69 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-runtime-budget-and-shared-gates/index.html +67 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-runtime-budget-and-shared-gates.md +71 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-sentinel-expression-engine/index.html +49 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-sentinel-expression-engine.md +70 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-simulator-vs-rules-test-api/index.html +96 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-simulator-vs-rules-test-api.md +76 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-the-2-plus-modules-extension/index.html +58 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-the-2-plus-modules-extension.md +75 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-value-wrappers-design/index.html +62 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-value-wrappers-design.md +80 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-why-this-package-exists/index.html +34 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-why-this-package-exists.md +43 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-compare-rulesets-for-weakening/index.html +54 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-compare-rulesets-for-weakening.md +69 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-inspect-rules-via-the-ast/index.html +89 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-inspect-rules-via-the-ast.md +113 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-lint-rules-source/index.html +50 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-lint-rules-source.md +73 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-pin-request-time/index.html +47 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-pin-request-time.md +58 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-register-tools-with-an-agent/index.html +61 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-register-tools-with-an-agent.md +78 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-resolve-module-imports/index.html +92 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-resolve-module-imports.md +93 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-simulate-rules-locally/index.html +89 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-simulate-rules-locally.md +117 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-test-rules-against-firebase/index.html +70 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-test-rules-against-firebase.md +93 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-api/index.html +129 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-api.md +176 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-ast/index.html +85 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-ast.md +105 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-errors/index.html +63 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-errors.md +89 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-lint-rules/index.html +148 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-lint-rules.md +159 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-simulator-context/index.html +66 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-simulator-context.md +98 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-stdlib-modules/index.html +239 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-stdlib-modules.md +135 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-test-case-schema/index.html +93 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-test-case-schema.md +109 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-validator-findings/index.html +86 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-validator-findings.md +113 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-value-wrappers/index.html +101 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-value-wrappers.md +134 -0
- package/dist/serve/docs-ui/docs/pyric-rules-tutorials-01-lint-your-first-rules-file/index.html +107 -0
- package/dist/serve/docs-ui/docs/pyric-rules-tutorials-01-lint-your-first-rules-file.md +142 -0
- package/dist/serve/docs-ui/docs/pyric-rules-tutorials-02-write-a-test-suite-for-your-rules/index.html +151 -0
- package/dist/serve/docs-ui/docs/pyric-rules-tutorials-02-write-a-test-suite-for-your-rules.md +194 -0
- package/dist/serve/docs-ui/docs/pyric-rules.md +88 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox/index.html +67 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-every-op-is-a-request/index.html +141 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-every-op-is-a-request.md +157 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-identity-is-a-context/index.html +66 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-identity-is-a-context.md +98 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-internal-adapter-protocol/index.html +71 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-internal-adapter-protocol.md +105 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-listener-re-evaluation/index.html +56 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-listener-re-evaluation.md +80 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-local-backend-vs-firestore-offline/index.html +64 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-local-backend-vs-firestore-offline.md +56 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-why-adapters-are-siblings/index.html +88 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-why-adapters-are-siblings.md +87 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-why-this-package-exists/index.html +69 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-why-this-package-exists.md +57 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-multiple-isolated-sandboxes/index.html +63 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-multiple-isolated-sandboxes.md +83 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-observe-events/index.html +159 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-observe-events.md +154 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-pick-an-adapter/index.html +79 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-pick-an-adapter.md +69 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-replay-events/index.html +89 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-replay-events.md +87 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-reset-between-tests/index.html +68 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-reset-between-tests.md +86 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-seed-data-and-rules/index.html +91 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-seed-data-and-rules.md +112 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-switch-users/index.html +50 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-switch-users.md +70 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-use-admin-reads/index.html +54 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-use-admin-reads.md +73 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api/index.html +77 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api.md +117 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-divergences/index.html +125 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-divergences.md +137 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-error-codes/index.html +110 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-error-codes.md +114 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-internal-protocol/index.html +72 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-internal-protocol.md +99 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-sandbox-and-context/index.html +90 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-sandbox-and-context.md +128 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-sandbox-event/index.html +146 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-sandbox-event.md +188 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-snapshot-and-admin/index.html +53 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-snapshot-and-admin.md +77 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-tutorials-01-your-first-sandbox-session/index.html +115 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-tutorials-01-your-first-sandbox-session.md +154 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-tutorials-02-use-the-sandbox-in-a-test-harness/index.html +191 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-tutorials-02-use-the-sandbox-in-a-test-harness.md +222 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-tutorials-03-build-a-traffic-monitor/index.html +163 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-tutorials-03-build-a-traffic-monitor.md +192 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox.md +63 -0
- package/dist/serve/docs-ui/docs/pyric-storage/index.html +65 -0
- package/dist/serve/docs-ui/docs/pyric-storage-compat/index.html +1076 -0
- package/dist/serve/docs-ui/docs/pyric-storage-compat.md +337 -0
- package/dist/serve/docs-ui/docs/pyric-storage-explanation-implementation-scope/index.html +63 -0
- package/dist/serve/docs-ui/docs/pyric-storage-explanation-implementation-scope.md +104 -0
- package/dist/serve/docs-ui/docs/pyric-storage-explanation-session-archive-use-case/index.html +58 -0
- package/dist/serve/docs-ui/docs/pyric-storage-explanation-session-archive-use-case.md +80 -0
- package/dist/serve/docs-ui/docs/pyric-storage-explanation-why-indexeddb/index.html +50 -0
- package/dist/serve/docs-ui/docs/pyric-storage-explanation-why-indexeddb.md +82 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-enforce-rules/index.html +104 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-enforce-rules.md +111 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-list-and-delete/index.html +53 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-list-and-delete.md +76 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-round-trip-metadata/index.html +77 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-round-trip-metadata.md +100 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-switch-backends/index.html +65 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-switch-backends.md +82 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-test-rule-expressions/index.html +70 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-test-rule-expressions.md +82 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-api/index.html +92 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-api.md +152 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-error-codes/index.html +46 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-error-codes.md +66 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-rules-subset/index.html +73 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-rules-subset.md +90 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-storage-options/index.html +45 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-storage-options.md +65 -0
- package/dist/serve/docs-ui/docs/pyric-storage-tutorials-01-upload-and-download/index.html +114 -0
- package/dist/serve/docs-ui/docs/pyric-storage-tutorials-01-upload-and-download.md +141 -0
- package/dist/serve/docs-ui/docs/pyric-storage.md +63 -0
- package/dist/serve/docs-ui/docs/pyric-tools/index.html +45 -0
- package/dist/serve/docs-ui/docs/pyric-tools-bridge/index.html +71 -0
- package/dist/serve/docs-ui/docs/pyric-tools-bridge.md +90 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy/index.html +59 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-explanation-primitives-vs-orchestrators/index.html +63 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-explanation-primitives-vs-orchestrators.md +83 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-explanation-token-caching/index.html +47 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-explanation-token-caching.md +70 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-explanation-why-no-firebase-cli/index.html +36 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-explanation-why-no-firebase-cli.md +50 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-explanation-why-this-package-exists/index.html +47 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-explanation-why-this-package-exists.md +60 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-build-projectscope-from-firebase-auth/index.html +55 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-build-projectscope-from-firebase-auth.md +68 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-build-projectscope-from-service-account/index.html +35 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-build-projectscope-from-service-account.md +52 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-bundle-and-deploy-a-function/index.html +81 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-bundle-and-deploy-a-function.md +98 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-deploy-firestore-indexes/index.html +71 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-deploy-firestore-indexes.md +91 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-deploy-firestore-rules/index.html +100 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-deploy-firestore-rules.md +105 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-deploy-hosting-rewrites/index.html +86 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-deploy-hosting-rewrites.md +92 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-deploy-realtime-database-rules/index.html +132 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-deploy-realtime-database-rules.md +165 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-deploy-to-a-preview-channel/index.html +46 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-deploy-to-a-preview-channel.md +62 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-handle-errors-and-outcomes/index.html +75 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-handle-errors-and-outcomes.md +94 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-provision-a-firestore-database/index.html +48 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-provision-a-firestore-database.md +65 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-register-tools-with-an-agent/index.html +65 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-register-tools-with-an-agent.md +82 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-api/index.html +155 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-api.md +190 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-cli-agent-io/index.html +84 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-cli-agent-io.md +66 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-error-codes/index.html +71 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-error-codes.md +102 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-firestore-namespace/index.html +138 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-firestore-namespace.md +175 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-functions-namespace/index.html +105 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-functions-namespace.md +133 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-hosting-config/index.html +194 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-hosting-config.md +95 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-hosting-namespace/index.html +99 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-hosting-namespace.md +126 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-rtdb-namespace/index.html +110 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-rtdb-namespace.md +133 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-scope-and-outcome/index.html +68 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-scope-and-outcome.md +88 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-tool-factories/index.html +160 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-tool-factories.md +104 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-tutorials-01-deploy-a-cloud-function/index.html +88 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-tutorials-01-deploy-a-cloud-function.md +119 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy.md +52 -0
- package/dist/serve/docs-ui/docs/pyric-tools-how-to-build-a-standalone-binary/index.html +92 -0
- package/dist/serve/docs-ui/docs/pyric-tools-how-to-build-a-standalone-binary.md +95 -0
- package/dist/serve/docs-ui/docs/pyric-tools-how-to-configure-auth-providers-and-domains/index.html +101 -0
- package/dist/serve/docs-ui/docs/pyric-tools-how-to-configure-auth-providers-and-domains.md +126 -0
- package/dist/serve/docs-ui/docs/pyric-tools-how-to-discover-a-schema-from-firestore/index.html +95 -0
- package/dist/serve/docs-ui/docs/pyric-tools-how-to-discover-a-schema-from-firestore.md +119 -0
- package/dist/serve/docs-ui/docs/pyric-tools-how-to-promote-sandbox-state-to-a-fixture/index.html +52 -0
- package/dist/serve/docs-ui/docs/pyric-tools-how-to-promote-sandbox-state-to-a-fixture.md +83 -0
- package/dist/serve/docs-ui/docs/pyric-tools-how-to-serve-persistence-and-multi-tab/index.html +232 -0
- package/dist/serve/docs-ui/docs/pyric-tools-how-to-serve-persistence-and-multi-tab.md +178 -0
- package/dist/serve/docs-ui/docs/pyric-tools-how-to-use-the-vite-plugin/index.html +340 -0
- package/dist/serve/docs-ui/docs/pyric-tools-how-to-use-the-vite-plugin.md +288 -0
- package/dist/serve/docs-ui/docs/pyric-tools-how-to-verify-against-a-captured-session/index.html +128 -0
- package/dist/serve/docs-ui/docs/pyric-tools-how-to-verify-against-a-captured-session.md +173 -0
- package/dist/serve/docs-ui/docs/pyric-tools-reference-cli/index.html +433 -0
- package/dist/serve/docs-ui/docs/pyric-tools-reference-cli.md +252 -0
- package/dist/serve/docs-ui/docs/pyric-tools-reference-verify/index.html +81 -0
- package/dist/serve/docs-ui/docs/pyric-tools-reference-verify.md +98 -0
- package/dist/serve/docs-ui/docs/pyric-tools-tutorials-getting-started/index.html +92 -0
- package/dist/serve/docs-ui/docs/pyric-tools-tutorials-getting-started.md +117 -0
- package/dist/serve/docs-ui/docs/pyric-tools-tutorials-server-adoption/index.html +221 -0
- package/dist/serve/docs-ui/docs/pyric-tools-tutorials-server-adoption.md +239 -0
- package/dist/serve/docs-ui/docs/pyric-tools-tutorials-wire-claude-code/index.html +205 -0
- package/dist/serve/docs-ui/docs/pyric-tools-tutorials-wire-claude-code.md +250 -0
- package/dist/serve/docs-ui/docs/pyric-tools.md +47 -0
- package/dist/serve/docs-ui/docs/ui/index.html +76 -0
- package/dist/serve/docs-ui/docs/ui-auth-authsigninhelper/index.html +194 -0
- package/dist/serve/docs-ui/docs/ui-auth-authsigninhelper.md +108 -0
- package/dist/serve/docs-ui/docs/ui-auth-authusers/index.html +258 -0
- package/dist/serve/docs-ui/docs/ui-auth-authusers.md +174 -0
- package/dist/serve/docs-ui/docs/ui-firestore-collectionlist/index.html +92 -0
- package/dist/serve/docs-ui/docs/ui-firestore-collectionlist.md +71 -0
- package/dist/serve/docs-ui/docs/ui-firestore-deletewithconfirm/index.html +128 -0
- package/dist/serve/docs-ui/docs/ui-firestore-deletewithconfirm.md +94 -0
- package/dist/serve/docs-ui/docs/ui-firestore-documenteditor/index.html +154 -0
- package/dist/serve/docs-ui/docs/ui-firestore-documenteditor.md +107 -0
- package/dist/serve/docs-ui/docs/ui-firestore-documentlist/index.html +132 -0
- package/dist/serve/docs-ui/docs/ui-firestore-documentlist.md +86 -0
- package/dist/serve/docs-ui/docs/ui-firestore-documentpreview/index.html +159 -0
- package/dist/serve/docs-ui/docs/ui-firestore-documentpreview.md +78 -0
- package/dist/serve/docs-ui/docs/ui-firestore-querybuilder/index.html +104 -0
- package/dist/serve/docs-ui/docs/ui-firestore-querybuilder.md +95 -0
- package/dist/serve/docs-ui/docs/ui-firestore-referencepicker/index.html +113 -0
- package/dist/serve/docs-ui/docs/ui-firestore-referencepicker.md +85 -0
- package/dist/serve/docs-ui/docs/ui-primitives-badge/index.html +56 -0
- package/dist/serve/docs-ui/docs/ui-primitives-badge.md +34 -0
- package/dist/serve/docs-ui/docs/ui-primitives-confirmdialog/index.html +140 -0
- package/dist/serve/docs-ui/docs/ui-primitives-confirmdialog.md +98 -0
- package/dist/serve/docs-ui/docs/ui-primitives-copybutton/index.html +58 -0
- package/dist/serve/docs-ui/docs/ui-primitives-copybutton.md +31 -0
- package/dist/serve/docs-ui/docs/ui-primitives-jsonview/index.html +58 -0
- package/dist/serve/docs-ui/docs/ui-primitives-jsonview.md +41 -0
- package/dist/serve/docs-ui/docs/ui-primitives-segmentedcontrol/index.html +70 -0
- package/dist/serve/docs-ui/docs/ui-primitives-segmentedcontrol.md +44 -0
- package/dist/serve/docs-ui/docs/ui-primitives-toast/index.html +87 -0
- package/dist/serve/docs-ui/docs/ui-primitives-toast.md +74 -0
- package/dist/serve/docs-ui/docs/ui-primitives-virtuallist/index.html +85 -0
- package/dist/serve/docs-ui/docs/ui-primitives-virtuallist.md +48 -0
- package/dist/serve/docs-ui/docs/ui-storage/index.html +154 -0
- package/dist/serve/docs-ui/docs/ui-storage-deleteselectionwithconfirm/index.html +127 -0
- package/dist/serve/docs-ui/docs/ui-storage-deleteselectionwithconfirm.md +83 -0
- package/dist/serve/docs-ui/docs/ui-storage-objectbrowser/index.html +137 -0
- package/dist/serve/docs-ui/docs/ui-storage-objectbrowser.md +84 -0
- package/dist/serve/docs-ui/docs/ui-storage-objectinspector/index.html +139 -0
- package/dist/serve/docs-ui/docs/ui-storage-objectinspector.md +87 -0
- package/dist/serve/docs-ui/docs/ui-storage-pathbreadcrumb/index.html +72 -0
- package/dist/serve/docs-ui/docs/ui-storage-pathbreadcrumb.md +51 -0
- package/dist/serve/docs-ui/docs/ui-storage-rules-aware-affordances/index.html +65 -0
- package/dist/serve/docs-ui/docs/ui-storage-rules-aware-affordances.md +53 -0
- package/dist/serve/docs-ui/docs/ui-storage-uploaddropzone/index.html +93 -0
- package/dist/serve/docs-ui/docs/ui-storage-uploaddropzone.md +72 -0
- package/dist/serve/docs-ui/docs/ui-storage-usestoragerulesgate/index.html +153 -0
- package/dist/serve/docs-ui/docs/ui-storage-usestoragerulesgate.md +105 -0
- package/dist/serve/docs-ui/docs/ui-storage.md +165 -0
- package/dist/serve/docs-ui/docs/ui-traffic/index.html +88 -0
- package/dist/serve/docs-ui/docs/ui-traffic-ruleheatmap/index.html +79 -0
- package/dist/serve/docs-ui/docs/ui-traffic-ruleheatmap.md +54 -0
- package/dist/serve/docs-ui/docs/ui-traffic-trafficdetail/index.html +78 -0
- package/dist/serve/docs-ui/docs/ui-traffic-trafficdetail.md +53 -0
- package/dist/serve/docs-ui/docs/ui-traffic-trafficlog/index.html +118 -0
- package/dist/serve/docs-ui/docs/ui-traffic-trafficlog.md +63 -0
- package/dist/serve/docs-ui/docs/ui-traffic-trafficstats/index.html +51 -0
- package/dist/serve/docs-ui/docs/ui-traffic-trafficstats.md +40 -0
- package/dist/serve/docs-ui/docs/ui-traffic.md +96 -0
- package/dist/serve/docs-ui/docs/ui.md +88 -0
- package/dist/serve/docs-ui/index.html +1 -0
- package/dist/serve/docs-ui/llms.txt +221 -0
- package/dist/serve/entries/app.d.ts +26 -0
- package/dist/serve/entries/app.d.ts.map +1 -0
- package/dist/serve/entries/app.js +51 -0
- package/dist/serve/entries/app.js.map +1 -0
- package/dist/serve/entries/auth-helper-core.d.ts +47 -0
- package/dist/serve/entries/auth-helper-core.d.ts.map +1 -0
- package/dist/serve/entries/auth-helper-core.js +121 -0
- package/dist/serve/entries/auth-helper-core.js.map +1 -0
- package/dist/serve/entries/auth-helper-dom.d.ts +14 -0
- package/dist/serve/entries/auth-helper-dom.d.ts.map +1 -0
- package/dist/serve/entries/auth-helper-dom.js +116 -0
- package/dist/serve/entries/auth-helper-dom.js.map +1 -0
- package/dist/serve/entries/auth.d.ts +62 -0
- package/dist/serve/entries/auth.d.ts.map +1 -0
- package/dist/serve/entries/auth.js +128 -0
- package/dist/serve/entries/auth.js.map +1 -0
- package/dist/serve/entries/bridge-url.d.ts +25 -0
- package/dist/serve/entries/bridge-url.d.ts.map +1 -0
- package/dist/serve/entries/bridge-url.js +30 -0
- package/dist/serve/entries/bridge-url.js.map +1 -0
- package/dist/serve/entries/database.d.ts +34 -0
- package/dist/serve/entries/database.d.ts.map +1 -0
- package/dist/serve/entries/database.js +42 -0
- package/dist/serve/entries/database.js.map +1 -0
- package/dist/serve/entries/firestore.d.ts +68 -0
- package/dist/serve/entries/firestore.d.ts.map +1 -0
- package/dist/serve/entries/firestore.js +115 -0
- package/dist/serve/entries/firestore.js.map +1 -0
- package/dist/serve/entries/init.d.ts +2 -0
- package/dist/serve/entries/init.d.ts.map +1 -0
- package/dist/serve/entries/init.js +14 -0
- package/dist/serve/entries/init.js.map +1 -0
- package/dist/serve/entries/keepalive.d.ts +20 -0
- package/dist/serve/entries/keepalive.d.ts.map +1 -0
- package/dist/serve/entries/keepalive.js +38 -0
- package/dist/serve/entries/keepalive.js.map +1 -0
- package/dist/serve/entries/runtime.d.ts +60 -0
- package/dist/serve/entries/runtime.d.ts.map +1 -0
- package/dist/serve/entries/runtime.js +555 -0
- package/dist/serve/entries/runtime.js.map +1 -0
- package/dist/serve/entries/session-store.d.ts +45 -0
- package/dist/serve/entries/session-store.d.ts.map +1 -0
- package/dist/serve/entries/session-store.js +71 -0
- package/dist/serve/entries/session-store.js.map +1 -0
- package/dist/serve/entries/storage.d.ts +23 -0
- package/dist/serve/entries/storage.d.ts.map +1 -0
- package/dist/serve/entries/storage.js +49 -0
- package/dist/serve/entries/storage.js.map +1 -0
- package/dist/serve/entries/tab-sync-wiring.d.ts +88 -0
- package/dist/serve/entries/tab-sync-wiring.d.ts.map +1 -0
- package/dist/serve/entries/tab-sync-wiring.js +217 -0
- package/dist/serve/entries/tab-sync-wiring.js.map +1 -0
- package/dist/serve/namespace.d.ts +93 -0
- package/dist/serve/namespace.d.ts.map +1 -0
- package/dist/serve/namespace.js +367 -0
- package/dist/serve/namespace.js.map +1 -0
- package/dist/serve/open-browser.d.ts +23 -0
- package/dist/serve/open-browser.d.ts.map +1 -0
- package/dist/serve/open-browser.js +58 -0
- package/dist/serve/open-browser.js.map +1 -0
- package/dist/serve/playground-ui/_astro/HomePage.BFOjZGZp.js +2 -0
- package/dist/serve/playground-ui/_astro/PlaygroundPage.3jki8il0.js +3300 -0
- package/dist/serve/playground-ui/_astro/PlaygroundPage.MhP_vFvK.css +32 -0
- package/dist/serve/playground-ui/_astro/TopBar.ChifCjLD.js +5025 -0
- package/dist/serve/playground-ui/_astro/client.D61DpmEZ.js +274 -0
- package/dist/serve/playground-ui/_astro/client.GCK88uRs.js +1 -0
- package/dist/serve/playground-ui/_astro/esbuild.BHljloGq.wasm +0 -0
- package/dist/serve/playground-ui/_astro/index.B9aLOeXL.js +29 -0
- package/dist/serve/playground-ui/_astro/index.BTKE7uRF.js +1227 -0
- package/dist/serve/playground-ui/_astro/index.BfCthstx.css +1 -0
- package/dist/serve/playground-ui/_astro/index.Mr0Dtjih.js +342 -0
- package/dist/serve/playground-ui/_astro/ort-wasm-simd-threaded.asyncify.DMmc6YqF.wasm +0 -0
- package/dist/serve/playground-ui/favicon.svg +4 -0
- package/dist/serve/playground-ui/index.html +2 -0
- package/dist/serve/playground-ui/playground/index.html +2 -0
- package/dist/serve/rules.d.ts +45 -0
- package/dist/serve/rules.d.ts.map +1 -0
- package/dist/serve/rules.js +139 -0
- package/dist/serve/rules.js.map +1 -0
- package/dist/serve/sandbox-marker.d.ts +9 -0
- package/dist/serve/sandbox-marker.d.ts.map +1 -0
- package/dist/serve/sandbox-marker.js +32 -0
- package/dist/serve/sandbox-marker.js.map +1 -0
- package/dist/serve/server.d.ts +135 -0
- package/dist/serve/server.d.ts.map +1 -0
- package/dist/serve/server.js +328 -0
- package/dist/serve/server.js.map +1 -0
- package/dist/serve/standalone-assets.d.ts +66 -0
- package/dist/serve/standalone-assets.d.ts.map +1 -0
- package/dist/serve/standalone-assets.js +144 -0
- package/dist/serve/standalone-assets.js.map +1 -0
- package/dist/serve/state-store.d.ts +45 -0
- package/dist/serve/state-store.d.ts.map +1 -0
- package/dist/serve/state-store.js +120 -0
- package/dist/serve/state-store.js.map +1 -0
- package/dist/serve/studio/disk-project-store.d.ts +9 -0
- package/dist/serve/studio/disk-project-store.d.ts.map +1 -0
- package/dist/serve/studio/disk-project-store.js +173 -0
- package/dist/serve/studio/disk-project-store.js.map +1 -0
- package/dist/serve/studio/disk-workspace.d.ts +14 -0
- package/dist/serve/studio/disk-workspace.d.ts.map +1 -0
- package/dist/serve/studio/disk-workspace.js +152 -0
- package/dist/serve/studio/disk-workspace.js.map +1 -0
- package/dist/serve/studio/index.d.ts +10 -0
- package/dist/serve/studio/index.d.ts.map +1 -0
- package/dist/serve/studio/index.js +9 -0
- package/dist/serve/studio/index.js.map +1 -0
- package/dist/serve/studio/routes.d.ts +40 -0
- package/dist/serve/studio/routes.d.ts.map +1 -0
- package/dist/serve/studio/routes.js +182 -0
- package/dist/serve/studio/routes.js.map +1 -0
- package/dist/serve/studio/store-types.d.ts +45 -0
- package/dist/serve/studio/store-types.d.ts.map +1 -0
- package/dist/serve/studio/store-types.js +11 -0
- package/dist/serve/studio/store-types.js.map +1 -0
- package/dist/serve/studio-ui/assets/RulesCodeEditor-Bncteb8z.js +23 -0
- package/dist/serve/studio-ui/assets/index-CmkJxFcG.js +4577 -0
- package/dist/serve/studio-ui/assets/index-DNK39P6C.css +1 -0
- package/dist/serve/studio-ui/assets/seed-Bab4ArXQ.js +2 -0
- package/dist/serve/studio-ui/index.html +32 -0
- package/dist/serve/studio-ui/pyric-logo.svg +76 -0
- package/dist/serve/vite-plugin.d.ts +57 -0
- package/dist/serve/vite-plugin.d.ts.map +1 -0
- package/dist/serve/vite-plugin.js +687 -0
- package/dist/serve/vite-plugin.js.map +1 -0
- package/dist/serve/worker/client.d.ts +668 -0
- package/dist/serve/worker/client.d.ts.map +1 -0
- package/dist/serve/worker/client.js +1635 -0
- package/dist/serve/worker/client.js.map +1 -0
- package/dist/serve/worker/entry.d.ts +40 -0
- package/dist/serve/worker/entry.d.ts.map +1 -0
- package/dist/serve/worker/entry.js +122 -0
- package/dist/serve/worker/entry.js.map +1 -0
- package/dist/serve/worker/host-auth.d.ts +47 -0
- package/dist/serve/worker/host-auth.d.ts.map +1 -0
- package/dist/serve/worker/host-auth.js +434 -0
- package/dist/serve/worker/host-auth.js.map +1 -0
- package/dist/serve/worker/host-context.d.ts +180 -0
- package/dist/serve/worker/host-context.d.ts.map +1 -0
- package/dist/serve/worker/host-context.js +45 -0
- package/dist/serve/worker/host-context.js.map +1 -0
- package/dist/serve/worker/host-events.d.ts +21 -0
- package/dist/serve/worker/host-events.d.ts.map +1 -0
- package/dist/serve/worker/host-events.js +87 -0
- package/dist/serve/worker/host-events.js.map +1 -0
- package/dist/serve/worker/host.d.ts +81 -0
- package/dist/serve/worker/host.d.ts.map +1 -0
- package/dist/serve/worker/host.js +1605 -0
- package/dist/serve/worker/host.js.map +1 -0
- package/dist/serve/worker/index.d.ts +22 -0
- package/dist/serve/worker/index.d.ts.map +1 -0
- package/dist/serve/worker/index.js +61 -0
- package/dist/serve/worker/index.js.map +1 -0
- package/dist/serve/worker/protocol.d.ts +955 -0
- package/dist/serve/worker/protocol.d.ts.map +1 -0
- package/dist/serve/worker/protocol.js +197 -0
- package/dist/serve/worker/protocol.js.map +1 -0
- package/dist/serve/worker/serve-init.d.ts +192 -0
- package/dist/serve/worker/serve-init.d.ts.map +1 -0
- package/dist/serve/worker/serve-init.js +555 -0
- package/dist/serve/worker/serve-init.js.map +1 -0
- package/dist/serve/writer-lock.d.ts +32 -0
- package/dist/serve/writer-lock.d.ts.map +1 -0
- package/dist/serve/writer-lock.js +43 -0
- package/dist/serve/writer-lock.js.map +1 -0
- package/dist/verify/cases.d.ts +37 -0
- package/dist/verify/cases.d.ts.map +1 -0
- package/dist/verify/cases.js +173 -0
- package/dist/verify/cases.js.map +1 -0
- package/dist/verify/fixture.d.ts +79 -0
- package/dist/verify/fixture.d.ts.map +1 -0
- package/dist/verify/fixture.js +114 -0
- package/dist/verify/fixture.js.map +1 -0
- package/dist/verify/index.d.ts +102 -0
- package/dist/verify/index.d.ts.map +1 -0
- package/dist/verify/index.js +318 -0
- package/dist/verify/index.js.map +1 -0
- package/dist/verify/tools.d.ts +7 -0
- package/dist/verify/tools.d.ts.map +1 -0
- package/dist/verify/tools.js +83 -0
- package/dist/verify/tools.js.map +1 -0
- package/dist/vite.d.ts +12 -0
- package/dist/vite.d.ts.map +1 -0
- package/dist/vite.js +16 -0
- package/dist/vite.js.map +1 -0
- package/package.json +127 -0
|
@@ -0,0 +1,1635 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worker client SDK — mirrors `pyric/firestore` for the SharedWorker path.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS EXISTS
|
|
5
|
+
* ---------------
|
|
6
|
+
* When the SharedWorker is available, app code should be able to swap its
|
|
7
|
+
* `pyric/firestore` import for this module (via an import-map) and have
|
|
8
|
+
* every operation transparently route to the single worker-hosted sandbox
|
|
9
|
+
* instead of running an in-page sandbox. The API surface is identical:
|
|
10
|
+
* same function names, same argument shapes, same return types.
|
|
11
|
+
*
|
|
12
|
+
* DESIGN SPLIT
|
|
13
|
+
* ------------
|
|
14
|
+
* Client-side only (no RPC — build descriptor objects in-page):
|
|
15
|
+
* `getFirestore`, `doc`, `collection`, `collectionGroup`, `query`,
|
|
16
|
+
* `where`, `orderBy`, `limit`, `limitToLast`, `startAt`, `startAfter`,
|
|
17
|
+
* `endAt`, `endBefore`
|
|
18
|
+
*
|
|
19
|
+
* These return `ClientDb`, `DocRefHandle`, `CollRefHandle`, `QueryHandle`
|
|
20
|
+
* objects that carry the port + a serializable descriptor. No RPC fires
|
|
21
|
+
* until an execution function is called.
|
|
22
|
+
*
|
|
23
|
+
* WHY IN-PAGE: Firebase's `doc()` / `collection()` / `query()` are
|
|
24
|
+
* synchronous — they build ref objects. Making them async (RPC) would
|
|
25
|
+
* break every existing app pattern. Since path-building needs no data
|
|
26
|
+
* from the sandbox, it's correct and cheap to do it in-page.
|
|
27
|
+
*
|
|
28
|
+
* Sentinel factories (client-side markers, worker resolves them):
|
|
29
|
+
* `serverTimestamp`, `increment`, `arrayUnion`, `arrayRemove`, `deleteField`
|
|
30
|
+
*
|
|
31
|
+
* Return `SentinelMarker` objects that embed in write data.
|
|
32
|
+
* The host's `resolveSentinels` converts them before writing.
|
|
33
|
+
*
|
|
34
|
+
* Execution functions (RPC — send op to worker, await reply):
|
|
35
|
+
* `getDoc`, `getDocs`, `setDoc`, `updateDoc`, `deleteDoc`, `addDoc`,
|
|
36
|
+
* `onSnapshot`, `getCountFromServer`, `runTransaction`, `writeBatch`
|
|
37
|
+
*
|
|
38
|
+
* TRANSACTION SEMANTICS + MULTI-TAB CORRECTNESS
|
|
39
|
+
* -----------------------------------------------
|
|
40
|
+
* `runTransaction(db, updateFn)` on the client:
|
|
41
|
+
* 1. Runs `updateFn(txn)` locally — `txn.get(ref)` RPCs a getDoc, records
|
|
42
|
+
* `{ path, data }` in the per-attempt read-set, returns the snapshot.
|
|
43
|
+
* 2. `txn.set/update/delete` buffer writes locally in `txn`.
|
|
44
|
+
* 3. When `updateFn` resolves, sends `{ method:'txnCommit', reads, writes }`.
|
|
45
|
+
* 4. The worker re-reads each read-set doc inside a sandbox transaction,
|
|
46
|
+
* compares the JSON-serialized current data against the recorded data,
|
|
47
|
+
* and aborts with `{ code:'aborted' }` on any mismatch.
|
|
48
|
+
* 5. On `aborted`, the client re-runs `updateFn` with a fresh txn object
|
|
49
|
+
* (up to 5 attempts). All other errors are propagated immediately.
|
|
50
|
+
*
|
|
51
|
+
* WHY RETRY IS NECESSARY (multi-tab gap):
|
|
52
|
+
* A transaction spans two messages: the `txn.get` RPC and `txnCommit`. Another
|
|
53
|
+
* tab can write to a read doc in between (the event loop is free between
|
|
54
|
+
* messages). Without read-set validation that produces a silent lost update.
|
|
55
|
+
* The retry loop mirrors real Firestore SDK behaviour.
|
|
56
|
+
*
|
|
57
|
+
* SNAPSHOT DESERIALIZATION
|
|
58
|
+
* ------------------------
|
|
59
|
+
* The worker sends document data as `{ json: string }` (SerializedDocData).
|
|
60
|
+
* `deserializeDocData` (protocol.ts) parses the JSON and calls
|
|
61
|
+
* `rehydrateDocValue` (from pyric/sandbox) to reconstruct REAL class
|
|
62
|
+
* instances — Timestamp with `.seconds`/`.nanos`, Bytes with `.data`, LatLng
|
|
63
|
+
* with `.lat`/`.lng`. The wire format == the IDB persistence format.
|
|
64
|
+
*/
|
|
65
|
+
import { deserializeDocData, bytesToBase64, base64ToBytes, storagePayloadTooLarge, MAX_STORAGE_OP_BYTES, } from './protocol.js';
|
|
66
|
+
// ─── Rehydration (class instance restoration) ─────────────────────────────
|
|
67
|
+
/**
|
|
68
|
+
* Deserialize doc data from wire form to real class instances.
|
|
69
|
+
*
|
|
70
|
+
* `deserializeDocData` (protocol.ts) now calls `rehydrateDocValue` from
|
|
71
|
+
* pyric/sandbox, which reconstructs REAL Timestamp, Bytes, and LatLng
|
|
72
|
+
* instances — not plain-object look-alikes. This means:
|
|
73
|
+
* - `snap.data().createdAt` is a real `Timestamp` with `.seconds`/`.nanos`
|
|
74
|
+
* - `snap.data().blob` is a real `Bytes` with `.data` (Uint8Array)
|
|
75
|
+
* - `snap.data().where` is a real `LatLng` with `.lat`/`.lng`
|
|
76
|
+
* Consumer code that uses `instanceof` checks or method calls will work
|
|
77
|
+
* correctly after deserialization.
|
|
78
|
+
*/
|
|
79
|
+
function rehydrateDocData(serialized) {
|
|
80
|
+
return deserializeDocData(serialized);
|
|
81
|
+
}
|
|
82
|
+
function lastSegment(path) {
|
|
83
|
+
return path.split('/').at(-1) ?? path;
|
|
84
|
+
}
|
|
85
|
+
// ─── Port + correlation machinery ─────────────────────────────────────────
|
|
86
|
+
let _opCounter = 0;
|
|
87
|
+
let _subCounter = 0;
|
|
88
|
+
function nextId() { return `op-${++_opCounter}`; }
|
|
89
|
+
function nextSubId() { return `sub-${++_subCounter}`; }
|
|
90
|
+
/**
|
|
91
|
+
* Pending RPC resolvers. Keyed by correlation id.
|
|
92
|
+
* Resolves with the `value` field on success; rejects with a typed error
|
|
93
|
+
* on failure.
|
|
94
|
+
*/
|
|
95
|
+
const _pending = new Map();
|
|
96
|
+
/**
|
|
97
|
+
* Active snapshot subscribers. Keyed by subId.
|
|
98
|
+
* `next` is the user-supplied callback; `error` is the optional error handler.
|
|
99
|
+
*/
|
|
100
|
+
const _snapSubs = new Map();
|
|
101
|
+
/**
|
|
102
|
+
* Active event-stream subscribers (Pyric Studio keystone). Keyed by subId.
|
|
103
|
+
* `next` receives each delivered BATCH of `SandboxEvent`s — the first batch is
|
|
104
|
+
* the initial `history()` snapshot, subsequent batches are single live events.
|
|
105
|
+
*/
|
|
106
|
+
const _eventSubs = new Map();
|
|
107
|
+
/** Wire up the port's onmessage handler (idempotent per-port). */
|
|
108
|
+
function wirePort(port) {
|
|
109
|
+
port.onmessage = (ev) => {
|
|
110
|
+
const msg = ev.data;
|
|
111
|
+
if (msg.t === 'res') {
|
|
112
|
+
const pending = _pending.get(msg.id);
|
|
113
|
+
if (!pending)
|
|
114
|
+
return;
|
|
115
|
+
_pending.delete(msg.id);
|
|
116
|
+
if (msg.ok) {
|
|
117
|
+
pending.resolve(msg.value);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
const err = new Error(msg.error.message);
|
|
121
|
+
err.code = msg.error.code;
|
|
122
|
+
// Structured denial context (spike gap 6): re-attach so consumers —
|
|
123
|
+
// and the bridge relay, which re-serializes thrown errors — see the
|
|
124
|
+
// same shape a local SandboxError carries.
|
|
125
|
+
if (msg.error.denialContext !== undefined) {
|
|
126
|
+
err.denialContext = msg.error.denialContext;
|
|
127
|
+
}
|
|
128
|
+
pending.reject(err);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
else if (msg.t === 'snap') {
|
|
132
|
+
const sub = _snapSubs.get(msg.subId);
|
|
133
|
+
if (!sub)
|
|
134
|
+
return;
|
|
135
|
+
// Auth snaps carry `SerializedUser | null` — a null value is a valid
|
|
136
|
+
// "signed out" payload, not an error, so guard the __error sniff.
|
|
137
|
+
const value = (msg.value ?? {});
|
|
138
|
+
if (value.__error) {
|
|
139
|
+
const errPayload = value.__error;
|
|
140
|
+
const err = new Error(errPayload.message);
|
|
141
|
+
err.code = errPayload.code;
|
|
142
|
+
if (errPayload.denialContext !== undefined)
|
|
143
|
+
err.denialContext = errPayload.denialContext;
|
|
144
|
+
// Surface an unobserved listener error instead of swallowing it — the
|
|
145
|
+
// worker-path twin of the in-page default (a denied listener after a
|
|
146
|
+
// rules change / sign-out must not fail silently on the page console).
|
|
147
|
+
if (sub.error)
|
|
148
|
+
sub.error(err);
|
|
149
|
+
else
|
|
150
|
+
console.error('pyric/firestore: Uncaught Error in snapshot listener:', err);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
sub.next(msg.value);
|
|
154
|
+
}
|
|
155
|
+
else if (msg.t === 'event') {
|
|
156
|
+
// Event-stream batch (Pyric Studio keystone). Plain JSON SandboxEvents —
|
|
157
|
+
// no rehydration. Deliver the whole batch to the registered subscriber.
|
|
158
|
+
const cb = _eventSubs.get(msg.subId);
|
|
159
|
+
if (cb)
|
|
160
|
+
cb(msg.events);
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
// ─── Auth lens (Pyric Studio) ──────────────────────────────────────────────
|
|
165
|
+
//
|
|
166
|
+
// The default per-op auth lens carried on every FIRESTORE DATA op this client
|
|
167
|
+
// sends. The host resolves a data handle from it (`lensDb` in host.ts):
|
|
168
|
+
// - `{ mode: 'app-session' }` (the default): the served app's own session.
|
|
169
|
+
// - `{ mode: 'as', uid }`: impersonate — rules evaluate as that user.
|
|
170
|
+
// - `{ mode: 'admin' }`: admin lens (rule bypass; see host.ts gap note).
|
|
171
|
+
//
|
|
172
|
+
// Studio sets this so its data grids / rules-debug "re-run as user" views run
|
|
173
|
+
// under the chosen identity without threading `actAs` through every call. AUTH
|
|
174
|
+
// ops (`auth.*`) and `getVersion` are NEVER lensed — they operate the worker's
|
|
175
|
+
// session, not data — so the lens is stamped only on the data-op path.
|
|
176
|
+
/** Module-level default lens. `undefined` ⇒ the worker treats the op as the
|
|
177
|
+
* app's session (the additive default — existing senders omit `actAs`). */
|
|
178
|
+
let _defaultLens;
|
|
179
|
+
/**
|
|
180
|
+
* Set the default auth lens applied to subsequent Firestore DATA ops from this
|
|
181
|
+
* client (Pyric Studio). Pass `{ mode: 'as', uid }` to read/write AS a user
|
|
182
|
+
* (rules apply), `{ mode: 'admin' }` for the admin lens, or
|
|
183
|
+
* `{ mode: 'app-session' }` / `undefined` to revert to the app's own session.
|
|
184
|
+
*
|
|
185
|
+
* The lens is process-wide for this client module (one served page = one
|
|
186
|
+
* worker port), mirroring how Studio drives a single active identity at a time.
|
|
187
|
+
* Auth ops are unaffected — they always operate the real session.
|
|
188
|
+
*/
|
|
189
|
+
export function setLens(lens) {
|
|
190
|
+
_defaultLens = lens && lens.mode === 'app-session' ? undefined : lens;
|
|
191
|
+
}
|
|
192
|
+
/** The active default lens (read-only view), for Studio UI to reflect state. */
|
|
193
|
+
export function getLens() {
|
|
194
|
+
return _defaultLens;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Module-level op-source declaration (Pyric Studio traffic attribution).
|
|
198
|
+
* When set, every op/sub message THIS CLIENT MODULE CONSTRUCTS is stamped
|
|
199
|
+
* `source: 'studio'` on the wire; the host maps that onto the unified
|
|
200
|
+
* event stream's `actor` field so Traffic can filter Studio's own
|
|
201
|
+
* viewer/editor ops out of the app's stream.
|
|
202
|
+
*
|
|
203
|
+
* Studio's live plane sets this once at connect (`connectWorkerLive`);
|
|
204
|
+
* the served APP page never calls it (its module instance stays
|
|
205
|
+
* untagged), and RELAYED frames bypass stamping entirely — the bridge
|
|
206
|
+
* relay ({@link relayWorkerOp} / {@link relayWorkerSub}) forwards remote
|
|
207
|
+
* frames verbatim through {@link rawRpc} / a direct postMessage, so a
|
|
208
|
+
* user's own admin-SDK traffic through the remote bridge is never
|
|
209
|
+
* mislabeled as Studio's even though it rides the same port.
|
|
210
|
+
*/
|
|
211
|
+
let _opIssuer;
|
|
212
|
+
/** Declare who issues the ops this client module constructs. See {@link _opIssuer}. */
|
|
213
|
+
export function setOpIssuer(source) {
|
|
214
|
+
_opIssuer = source;
|
|
215
|
+
}
|
|
216
|
+
/** Stamp the declared op source onto a client-constructed message. Ops and
|
|
217
|
+
* subscriptions only — control frames (`tool`, `unsub`) never carry it
|
|
218
|
+
* (agent tool-calls dispatched through this port must not inherit
|
|
219
|
+
* Studio's source; their inner ops are attributed by the host). */
|
|
220
|
+
function stampIssuer(msg) {
|
|
221
|
+
return _opIssuer && (msg.t === 'op' || msg.t === 'sub')
|
|
222
|
+
? { ...msg, issuer: _opIssuer }
|
|
223
|
+
: msg;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Send an already-final message and return a promise for its result — no
|
|
227
|
+
* stamping. The RELAY path ({@link relayWorkerOp}) sends through this so
|
|
228
|
+
* remote frames pass verbatim.
|
|
229
|
+
*/
|
|
230
|
+
function rawRpc(port, msg) {
|
|
231
|
+
return new Promise((resolve, reject) => {
|
|
232
|
+
const opMsg = msg;
|
|
233
|
+
_pending.set(opMsg.id, { resolve, reject: reject });
|
|
234
|
+
port.postMessage(msg);
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
/** Send a CLIENT-CONSTRUCTED message: stamps the declared op source, then sends. */
|
|
238
|
+
function rpc(port, msg) {
|
|
239
|
+
return rawRpc(port, stampIssuer(msg));
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Like {@link rpc} but stamps the active default auth lens onto the op message
|
|
243
|
+
* (Pyric Studio). Used by data-service ops so a `setLens(...)` choice
|
|
244
|
+
* carries per op without every call site threading `actAs`. Auth ops + version
|
|
245
|
+
* use the bare {@link rpc} so they never carry a lens.
|
|
246
|
+
*
|
|
247
|
+
* `actAs` is only attached when a lens is active — when none is set the wire
|
|
248
|
+
* message is byte-identical to before, preserving the additive contract.
|
|
249
|
+
*/
|
|
250
|
+
function dataRpc(port, msg) {
|
|
251
|
+
const withLens = _defaultLens ? { ...msg, actAs: _defaultLens } : msg;
|
|
252
|
+
return rpc(port, withLens);
|
|
253
|
+
}
|
|
254
|
+
// ─── Public API ────────────────────────────────────────────────────────────
|
|
255
|
+
/**
|
|
256
|
+
* Connect to the SharedWorker and return a client Firestore handle.
|
|
257
|
+
*
|
|
258
|
+
* Pass the URL of the SharedWorker script as `workerUrl`. Under `pyric dev`
|
|
259
|
+
* this is `/__pyric/sdk/worker.js`; for tests or standalone use, pass the path
|
|
260
|
+
* explicitly.
|
|
261
|
+
*
|
|
262
|
+
* `getFirestore` mirrors `pyric/firestore`'s `getFirestore(sandbox)` shape
|
|
263
|
+
* but returns a `ClientDb` backed by a `MessagePort` instead of a sandbox.
|
|
264
|
+
*/
|
|
265
|
+
export function getFirestore(workerUrl, name) {
|
|
266
|
+
if (typeof SharedWorker === 'undefined') {
|
|
267
|
+
throw new Error('SharedWorker is not available. ' +
|
|
268
|
+
'Open this page over http:// (not file://) and use a supported browser ' +
|
|
269
|
+
'(Chrome 4+, Firefox 29+, Safari 16.4+).');
|
|
270
|
+
}
|
|
271
|
+
const worker = new SharedWorker(workerUrl, {
|
|
272
|
+
type: 'classic',
|
|
273
|
+
name: name ?? 'pyric-shared-worker',
|
|
274
|
+
});
|
|
275
|
+
const port = worker.port;
|
|
276
|
+
port.start();
|
|
277
|
+
wirePort(port);
|
|
278
|
+
return { __kind: 'client-db', port };
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Ask the worker for its baked build version (staleness guard). The page
|
|
282
|
+
* compares it to the served bundle version and warns when a still-running OLD
|
|
283
|
+
* worker is older than what's served (a SharedWorker can't hot-update).
|
|
284
|
+
*/
|
|
285
|
+
export async function getWorkerVersion(db) {
|
|
286
|
+
const r = (await rpc(db.port, { t: 'op', id: nextId(), method: 'getVersion' }));
|
|
287
|
+
return r.version;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Ask the worker for its stable per-instance id (see host `INSTANCE_ID_KEY`).
|
|
291
|
+
* Studio renders a human-friendly form so a user can tell which sandbox instance
|
|
292
|
+
* they're looking at — the same `localhost:<port>` in a different browser profile
|
|
293
|
+
* is a SEPARATE sandbox (a separate SharedWorker + IndexedDB), and this is how
|
|
294
|
+
* the two are told apart.
|
|
295
|
+
*/
|
|
296
|
+
export async function getWorkerInstanceId(db) {
|
|
297
|
+
const r = (await rpc(db.port, { t: 'op', id: nextId(), method: 'getVersion' }));
|
|
298
|
+
return r.instanceId ?? '';
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Phase 2 (transfer): export the FULL sandbox state as a portable bundle string
|
|
302
|
+
* (the chunk format the persist layer uses, so wrapper types round-trip). Save
|
|
303
|
+
* it to a file and {@link importWorkerState} it into another instance.
|
|
304
|
+
*/
|
|
305
|
+
export async function exportWorkerState(db) {
|
|
306
|
+
const r = (await rpc(db.port, { t: 'op', id: nextId(), method: 'exportState' }));
|
|
307
|
+
return r.bundle;
|
|
308
|
+
}
|
|
309
|
+
/** Phase 2 (clobber): replace this sandbox's ENTIRE state with `bundle`. */
|
|
310
|
+
export async function importWorkerState(db, bundle) {
|
|
311
|
+
await rpc(db.port, { t: 'op', id: nextId(), method: 'importState', bundle });
|
|
312
|
+
}
|
|
313
|
+
/** Phase 3: save the live sandbox as a named branch (a saved state bundle). */
|
|
314
|
+
export async function saveWorkerBranch(db, name) {
|
|
315
|
+
await rpc(db.port, { t: 'op', id: nextId(), method: 'saveBranch', name });
|
|
316
|
+
}
|
|
317
|
+
/** Phase 3: list this instance's saved branch names. */
|
|
318
|
+
export async function listWorkerBranches(db) {
|
|
319
|
+
const r = (await rpc(db.port, { t: 'op', id: nextId(), method: 'listBranches' }));
|
|
320
|
+
return r.branches ?? [];
|
|
321
|
+
}
|
|
322
|
+
/** Phase 3 (clobber): switch the live sandbox to a named branch's state. */
|
|
323
|
+
export async function switchWorkerBranch(db, name) {
|
|
324
|
+
await rpc(db.port, { t: 'op', id: nextId(), method: 'switchBranch', name });
|
|
325
|
+
}
|
|
326
|
+
/** Phase 3: delete a named branch. */
|
|
327
|
+
export async function deleteWorkerBranch(db, name) {
|
|
328
|
+
await rpc(db.port, { t: 'op', id: nextId(), method: 'deleteBranch', name });
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Forward an agent tool-call to the worker so it executes against the SAME
|
|
332
|
+
* sandbox the app + Studio use. The worker runs the canonical tool dispatcher
|
|
333
|
+
* (`buildSandboxDispatcher`) and replies with the `{ ok, summary, data }`
|
|
334
|
+
* result. Used by the bridge peer on the worker path (`connectBridgePeer` in
|
|
335
|
+
* `entries/runtime.ts`) so the agent shares the one authoritative sandbox.
|
|
336
|
+
*/
|
|
337
|
+
export async function callTool(db, name, args) {
|
|
338
|
+
return (await rpc(db.port, { t: 'tool', id: nextId(), name, args }));
|
|
339
|
+
}
|
|
340
|
+
// ─── Generic worker relay (remote sandbox, slice 1) ────────────────────────
|
|
341
|
+
//
|
|
342
|
+
// The bridge peer forwards `worker-op` / `worker-sub` frames from the Node
|
|
343
|
+
// side (`connectRemoteSandbox`) into the SharedWorker through these two
|
|
344
|
+
// functions (see `workerRelay` in `bridge/client/bridge.ts` + the wiring in
|
|
345
|
+
// `entries/runtime.ts`). Ids are re-minted LOCALLY (`nextId`/`nextSubId`) so
|
|
346
|
+
// relayed traffic shares this page's pending/sub maps without any chance of
|
|
347
|
+
// colliding with the page's own ids — the bridge correlates by ITS frame id.
|
|
348
|
+
/**
|
|
349
|
+
* Relay one raw worker-protocol op into the SharedWorker. `op` is the op
|
|
350
|
+
* message minus `t`/`id` (the `WorkerOpPayload` wire shape); resolves with
|
|
351
|
+
* the worker's `res.value`, rejects with an Error carrying `.code`.
|
|
352
|
+
*/
|
|
353
|
+
export function relayWorkerOp(db, op) {
|
|
354
|
+
// rawRpc, NOT rpc: relayed frames must pass verbatim — the declared op
|
|
355
|
+
// source (`setOpIssuer`) covers only ops THIS client constructs, so
|
|
356
|
+
// bridge-relayed admin/agent traffic is never mislabeled as Studio's.
|
|
357
|
+
return rawRpc(db.port, { ...op, t: 'op', id: nextId() });
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Relay a raw worker-protocol subscription into the SharedWorker. `sub` is
|
|
361
|
+
* the sub message minus `t`/`subId` (the `WorkerSubPayload` wire shape).
|
|
362
|
+
* `onValue` receives every snap value VERBATIM — including the worker host's
|
|
363
|
+
* `{ __error: { code, message } }` establishment-failure convention (listener
|
|
364
|
+
* errors are re-wrapped into the same shape so the far side sees one form).
|
|
365
|
+
* Returns the unsubscribe function.
|
|
366
|
+
*
|
|
367
|
+
* The unified event stream (`target: 'events'`) is NOT relayable yet — its
|
|
368
|
+
* history batches aren't coalescible, so it needs bounded backpressure first
|
|
369
|
+
* (slice 2).
|
|
370
|
+
*/
|
|
371
|
+
export function relayWorkerSub(db, sub, onValue) {
|
|
372
|
+
if (sub.target === 'events') {
|
|
373
|
+
throw new Error('event-stream subscriptions cannot be relayed over the bridge yet (needs bounded backpressure — slice 2)');
|
|
374
|
+
}
|
|
375
|
+
const subId = nextSubId();
|
|
376
|
+
_snapSubs.set(subId, {
|
|
377
|
+
next: onValue,
|
|
378
|
+
error: (err) => onValue({
|
|
379
|
+
__error: {
|
|
380
|
+
code: err.code ?? 'unknown',
|
|
381
|
+
message: err instanceof Error ? err.message : String(err),
|
|
382
|
+
},
|
|
383
|
+
}),
|
|
384
|
+
});
|
|
385
|
+
db.port.postMessage({ ...sub, t: 'sub', subId });
|
|
386
|
+
return () => {
|
|
387
|
+
_snapSubs.delete(subId);
|
|
388
|
+
db.port.postMessage({ t: 'unsub', subId });
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
// ─── Path factories (client-side only — no RPC) ──────────────────────────
|
|
392
|
+
/**
|
|
393
|
+
* Build a document reference. Mirrors `pyric/firestore`'s `doc(db, path)`.
|
|
394
|
+
*
|
|
395
|
+
* WHY CLIENT-SIDE: Firebase's `doc()` is synchronous and path-only — it
|
|
396
|
+
* needs no data from the sandbox. We build a descriptor object here and
|
|
397
|
+
* include the port so execution calls can route to the worker.
|
|
398
|
+
*/
|
|
399
|
+
export function doc(parent, ...pathSegments) {
|
|
400
|
+
const port = 'port' in parent ? parent.port : parent.port;
|
|
401
|
+
let path;
|
|
402
|
+
if (parent.__kind === 'client-db') {
|
|
403
|
+
if (pathSegments.length === 0)
|
|
404
|
+
throw new TypeError('doc(db, path) requires a path segment.');
|
|
405
|
+
path = pathSegments.join('/');
|
|
406
|
+
}
|
|
407
|
+
else {
|
|
408
|
+
// parent is a CollRefHandle
|
|
409
|
+
const collPath = parent.descriptor.path;
|
|
410
|
+
path = pathSegments.length > 0
|
|
411
|
+
? `${collPath}/${pathSegments.join('/')}`
|
|
412
|
+
: collPath; // caller will get auto-id via addDoc; doc() without id is unusual
|
|
413
|
+
}
|
|
414
|
+
const descriptor = { __ref: 'doc', path };
|
|
415
|
+
return {
|
|
416
|
+
__kind: 'doc-ref',
|
|
417
|
+
descriptor,
|
|
418
|
+
port,
|
|
419
|
+
id: lastSegment(path),
|
|
420
|
+
path,
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Build a collection reference. Mirrors `pyric/firestore`'s `collection(db, path)`.
|
|
425
|
+
*/
|
|
426
|
+
export function collection(parent, ...pathSegments) {
|
|
427
|
+
const port = parent.port;
|
|
428
|
+
if (pathSegments.length === 0)
|
|
429
|
+
throw new TypeError('collection() requires a path segment.');
|
|
430
|
+
let path;
|
|
431
|
+
if (parent.__kind === 'client-db') {
|
|
432
|
+
path = pathSegments.join('/');
|
|
433
|
+
}
|
|
434
|
+
else {
|
|
435
|
+
const docPath = parent.descriptor.path;
|
|
436
|
+
path = `${docPath}/${pathSegments.join('/')}`;
|
|
437
|
+
}
|
|
438
|
+
const descriptor = { __ref: 'collection', path };
|
|
439
|
+
return {
|
|
440
|
+
__kind: 'coll-ref',
|
|
441
|
+
descriptor,
|
|
442
|
+
port,
|
|
443
|
+
id: lastSegment(path),
|
|
444
|
+
path,
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Build a collection-group query. Mirrors `pyric/firestore`'s `collectionGroup(db, id)`.
|
|
449
|
+
*/
|
|
450
|
+
export function collectionGroup(db, collectionId) {
|
|
451
|
+
const descriptor = {
|
|
452
|
+
__ref: 'query',
|
|
453
|
+
source: { __ref: 'group', collectionId },
|
|
454
|
+
constraints: [],
|
|
455
|
+
};
|
|
456
|
+
return { __kind: 'query', descriptor, port: db.port };
|
|
457
|
+
}
|
|
458
|
+
export function where(field, op, value) {
|
|
459
|
+
return { _descriptor: { kind: 'where', field, op, value } };
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Extract a constraint's FILTER descriptor for composite embedding — throws
|
|
463
|
+
* the same TypeError `pyric/firestore`'s `and()`/`or()` raise when handed a
|
|
464
|
+
* non-filter (`orderBy` / `limit` / cursors are not valid inside composites).
|
|
465
|
+
*/
|
|
466
|
+
function toFilterDescriptor(kind, c) {
|
|
467
|
+
const d = c._descriptor;
|
|
468
|
+
if (d.kind !== 'where' && d.kind !== 'and' && d.kind !== 'or') {
|
|
469
|
+
throw new TypeError(`pyric worker client: ${kind}() received a non-filter constraint (orderBy / limit are not valid here).`);
|
|
470
|
+
}
|
|
471
|
+
return d;
|
|
472
|
+
}
|
|
473
|
+
function composite(kind, filters) {
|
|
474
|
+
if (filters.length === 0) {
|
|
475
|
+
throw new TypeError(`pyric worker client: ${kind}() requires at least one filter argument.`);
|
|
476
|
+
}
|
|
477
|
+
return { _descriptor: { kind, filters: filters.map((f) => toFilterDescriptor(kind, f)) } };
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* OR composite filter — at least one operand must match. Operands must be
|
|
481
|
+
* filters (`where()`, or nested `or()`/`and()`). Mirrors `pyric/firestore`'s
|
|
482
|
+
* `or(...)`; the worker rebuilds it with the real modular factory.
|
|
483
|
+
*/
|
|
484
|
+
export function or(...filters) {
|
|
485
|
+
return composite('or', filters);
|
|
486
|
+
}
|
|
487
|
+
/** AND composite filter — every operand must match. See {@link or}. */
|
|
488
|
+
export function and(...filters) {
|
|
489
|
+
return composite('and', filters);
|
|
490
|
+
}
|
|
491
|
+
export function orderBy(field, direction) {
|
|
492
|
+
return { _descriptor: { kind: 'orderBy', field, direction } };
|
|
493
|
+
}
|
|
494
|
+
export function limit(n) {
|
|
495
|
+
return { _descriptor: { kind: 'limit', n } };
|
|
496
|
+
}
|
|
497
|
+
export function limitToLast(n) {
|
|
498
|
+
return { _descriptor: { kind: 'limitToLast', n } };
|
|
499
|
+
}
|
|
500
|
+
export function startAt(...values) {
|
|
501
|
+
return { _descriptor: { kind: 'startAt', values } };
|
|
502
|
+
}
|
|
503
|
+
export function startAfter(...values) {
|
|
504
|
+
return { _descriptor: { kind: 'startAfter', values } };
|
|
505
|
+
}
|
|
506
|
+
export function endAt(...values) {
|
|
507
|
+
return { _descriptor: { kind: 'endAt', values } };
|
|
508
|
+
}
|
|
509
|
+
export function endBefore(...values) {
|
|
510
|
+
return { _descriptor: { kind: 'endBefore', values } };
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Apply query constraints to a source ref or query.
|
|
514
|
+
* Mirrors `pyric/firestore`'s `query(source, ...constraints)`.
|
|
515
|
+
*/
|
|
516
|
+
export function query(source, ...constraints) {
|
|
517
|
+
const sourceDescriptor = source.__kind === 'coll-ref'
|
|
518
|
+
? source.descriptor
|
|
519
|
+
: source.descriptor;
|
|
520
|
+
const existingConstraints = source.__kind === 'query'
|
|
521
|
+
? source.descriptor.constraints
|
|
522
|
+
: [];
|
|
523
|
+
const descriptor = {
|
|
524
|
+
__ref: 'query',
|
|
525
|
+
source: sourceDescriptor.__ref === 'query'
|
|
526
|
+
? sourceDescriptor.source
|
|
527
|
+
: sourceDescriptor,
|
|
528
|
+
constraints: [
|
|
529
|
+
...existingConstraints,
|
|
530
|
+
...constraints.map((c) => c._descriptor),
|
|
531
|
+
],
|
|
532
|
+
};
|
|
533
|
+
return { __kind: 'query', descriptor, port: source.port };
|
|
534
|
+
}
|
|
535
|
+
// ─── Sentinel factories (client-side markers) ────────────────────────────
|
|
536
|
+
export function serverTimestamp() {
|
|
537
|
+
return { __sentinel: 'serverTimestamp' };
|
|
538
|
+
}
|
|
539
|
+
export function increment(n) {
|
|
540
|
+
return { __sentinel: 'increment', n };
|
|
541
|
+
}
|
|
542
|
+
export function arrayUnion(...values) {
|
|
543
|
+
return { __sentinel: 'arrayUnion', values };
|
|
544
|
+
}
|
|
545
|
+
export function arrayRemove(...values) {
|
|
546
|
+
return { __sentinel: 'arrayRemove', values };
|
|
547
|
+
}
|
|
548
|
+
export function deleteField() {
|
|
549
|
+
return { __sentinel: 'deleteField' };
|
|
550
|
+
}
|
|
551
|
+
function makeDocSnapshot(raw) {
|
|
552
|
+
const data = raw.exists && raw.data ? rehydrateDocData(raw.data) : undefined;
|
|
553
|
+
const path = raw.path ?? raw.id;
|
|
554
|
+
return {
|
|
555
|
+
id: raw.id,
|
|
556
|
+
path,
|
|
557
|
+
// The modular SDK contract (and `@pyric/ui`'s grids) read `snap.ref.path`
|
|
558
|
+
// off query docs; mirror it so the worker snapshot is a drop-in. A
|
|
559
|
+
// lightweight ref (id + path) is all consumers read; a full handle is
|
|
560
|
+
// rebuilt from the path when an op is needed.
|
|
561
|
+
ref: { id: raw.id, path },
|
|
562
|
+
exists: () => raw.exists,
|
|
563
|
+
data: () => data,
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
function makeQuerySnapshot(raw) {
|
|
567
|
+
const docs = raw.docs.map(makeDocSnapshot);
|
|
568
|
+
return {
|
|
569
|
+
size: docs.length,
|
|
570
|
+
empty: docs.length === 0,
|
|
571
|
+
docs,
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
// ─── Execution functions (RPC) ────────────────────────────────────────────
|
|
575
|
+
export async function getDoc(ref) {
|
|
576
|
+
const result = await dataRpc(ref.port, {
|
|
577
|
+
t: 'op',
|
|
578
|
+
id: nextId(),
|
|
579
|
+
method: 'getDoc',
|
|
580
|
+
path: ref.descriptor.path,
|
|
581
|
+
});
|
|
582
|
+
return makeDocSnapshot(result);
|
|
583
|
+
}
|
|
584
|
+
export async function getDocs(source) {
|
|
585
|
+
const result = await dataRpc(source.port, {
|
|
586
|
+
t: 'op',
|
|
587
|
+
id: nextId(),
|
|
588
|
+
method: 'getDocs',
|
|
589
|
+
source: source.__kind === 'coll-ref'
|
|
590
|
+
? source.descriptor
|
|
591
|
+
: source.descriptor,
|
|
592
|
+
});
|
|
593
|
+
return makeQuerySnapshot(result);
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* Enumerate root collection ids (Pyric Studio data browse). The modular SDK has
|
|
597
|
+
* no client `listCollections`, so the host scans the sandbox keyspace and
|
|
598
|
+
* returns the ids. Lens is attached (via dataRpc) but the host enumeration is
|
|
599
|
+
* lens-independent.
|
|
600
|
+
*/
|
|
601
|
+
export async function listRootCollections(db) {
|
|
602
|
+
const r = (await dataRpc(db.port, {
|
|
603
|
+
t: 'op',
|
|
604
|
+
id: nextId(),
|
|
605
|
+
method: 'listRootCollections',
|
|
606
|
+
}));
|
|
607
|
+
return r.ids;
|
|
608
|
+
}
|
|
609
|
+
/** Enumerate subcollection ids under a document path (Pyric Studio data browse). */
|
|
610
|
+
export async function listSubcollections(db, docPath) {
|
|
611
|
+
const r = (await dataRpc(db.port, {
|
|
612
|
+
t: 'op',
|
|
613
|
+
id: nextId(),
|
|
614
|
+
method: 'listSubcollections',
|
|
615
|
+
docPath,
|
|
616
|
+
}));
|
|
617
|
+
return r.ids;
|
|
618
|
+
}
|
|
619
|
+
export async function setDoc(ref, data, options) {
|
|
620
|
+
await dataRpc(ref.port, {
|
|
621
|
+
t: 'op',
|
|
622
|
+
id: nextId(),
|
|
623
|
+
method: 'setDoc',
|
|
624
|
+
path: ref.descriptor.path,
|
|
625
|
+
data,
|
|
626
|
+
options,
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
export async function updateDoc(ref, data) {
|
|
630
|
+
await dataRpc(ref.port, {
|
|
631
|
+
t: 'op',
|
|
632
|
+
id: nextId(),
|
|
633
|
+
method: 'updateDoc',
|
|
634
|
+
path: ref.descriptor.path,
|
|
635
|
+
data,
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
export async function deleteDoc(ref) {
|
|
639
|
+
await dataRpc(ref.port, {
|
|
640
|
+
t: 'op',
|
|
641
|
+
id: nextId(),
|
|
642
|
+
method: 'deleteDoc',
|
|
643
|
+
path: ref.descriptor.path,
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
export async function addDoc(coll, data) {
|
|
647
|
+
const result = await dataRpc(coll.port, {
|
|
648
|
+
t: 'op',
|
|
649
|
+
id: nextId(),
|
|
650
|
+
method: 'addDoc',
|
|
651
|
+
collectionPath: coll.descriptor.path,
|
|
652
|
+
data,
|
|
653
|
+
});
|
|
654
|
+
return {
|
|
655
|
+
__kind: 'doc-ref',
|
|
656
|
+
descriptor: { __ref: 'doc', path: result.path },
|
|
657
|
+
port: coll.port,
|
|
658
|
+
id: result.id,
|
|
659
|
+
path: result.path,
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
export async function getCountFromServer(source) {
|
|
663
|
+
const result = await dataRpc(source.port, {
|
|
664
|
+
t: 'op',
|
|
665
|
+
id: nextId(),
|
|
666
|
+
method: 'count',
|
|
667
|
+
source: source.__kind === 'coll-ref'
|
|
668
|
+
? source.descriptor
|
|
669
|
+
: source.descriptor,
|
|
670
|
+
});
|
|
671
|
+
return { data: () => ({ count: result.count }) };
|
|
672
|
+
}
|
|
673
|
+
// ─── Multi-field aggregates (count / sum / average) ───────────────────────
|
|
674
|
+
/** Factory: count() aggregate field. Mirrors `pyric/firestore`'s `count()`. */
|
|
675
|
+
export function count() {
|
|
676
|
+
return { kind: 'count' };
|
|
677
|
+
}
|
|
678
|
+
/** Factory: sum-of-`field` aggregate. Mirrors `pyric/firestore`'s `sum()`. */
|
|
679
|
+
export function sum(field) {
|
|
680
|
+
return { kind: 'sum', field };
|
|
681
|
+
}
|
|
682
|
+
/** Factory: average-of-`field` aggregate. Empty input yields `null`. */
|
|
683
|
+
export function average(field) {
|
|
684
|
+
return { kind: 'average', field };
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* Run a multi-field aggregate on the worker. Mirrors `pyric/firestore`'s
|
|
688
|
+
* `getAggregateFromServer(query, spec)`: spec entries are keyed by
|
|
689
|
+
* caller-chosen aliases; `.data()` returns the numbers under the same keys
|
|
690
|
+
* (`average` over no rows is `null`).
|
|
691
|
+
*/
|
|
692
|
+
export async function getAggregateFromServer(source, spec) {
|
|
693
|
+
const result = await dataRpc(source.port, {
|
|
694
|
+
t: 'op',
|
|
695
|
+
id: nextId(),
|
|
696
|
+
method: 'aggregate',
|
|
697
|
+
source: source.__kind === 'coll-ref'
|
|
698
|
+
? source.descriptor
|
|
699
|
+
: source.descriptor,
|
|
700
|
+
spec,
|
|
701
|
+
});
|
|
702
|
+
return { data: () => result.data };
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* Subscribe to a document or query. Mirrors `pyric/firestore`'s `onSnapshot`.
|
|
706
|
+
*
|
|
707
|
+
* Returns an `unsub` function. Sends `{ t:'unsub', subId }` to the worker
|
|
708
|
+
* to deregister the listener on the worker side.
|
|
709
|
+
*/
|
|
710
|
+
export function onSnapshot(target, callback, errorCallback) {
|
|
711
|
+
const subId = nextSubId();
|
|
712
|
+
const port = target.port;
|
|
713
|
+
_snapSubs.set(subId, {
|
|
714
|
+
next: (raw) => {
|
|
715
|
+
const r = raw;
|
|
716
|
+
if ('docs' in r) {
|
|
717
|
+
callback(makeQuerySnapshot(r));
|
|
718
|
+
}
|
|
719
|
+
else {
|
|
720
|
+
callback(makeDocSnapshot(r));
|
|
721
|
+
}
|
|
722
|
+
},
|
|
723
|
+
error: errorCallback,
|
|
724
|
+
});
|
|
725
|
+
const descriptor = target.__kind === 'doc-ref'
|
|
726
|
+
? target.descriptor
|
|
727
|
+
: target.__kind === 'coll-ref'
|
|
728
|
+
? target.descriptor
|
|
729
|
+
: target.descriptor;
|
|
730
|
+
// Stamp the active default lens onto the sub (Pyric Studio "watch as user")
|
|
731
|
+
// exactly as `dataRpc` does for ops, so a `setLens({mode:'as',uid})` choice
|
|
732
|
+
// makes listeners impersonate too. Omitted when no lens is set → byte-identical
|
|
733
|
+
// wire message, preserving the additive contract. The declared op source
|
|
734
|
+
// rides along the same way (client-constructed subs only — the relay's
|
|
735
|
+
// subs post verbatim).
|
|
736
|
+
port.postMessage(stampIssuer((_defaultLens
|
|
737
|
+
? { t: 'sub', subId, target: descriptor, actAs: _defaultLens }
|
|
738
|
+
: { t: 'sub', subId, target: descriptor })));
|
|
739
|
+
return () => {
|
|
740
|
+
_snapSubs.delete(subId);
|
|
741
|
+
port.postMessage({ t: 'unsub', subId });
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
export function writeBatch(db) {
|
|
745
|
+
const writes = [];
|
|
746
|
+
const port = db.port;
|
|
747
|
+
const batch = {
|
|
748
|
+
set(ref, data, options) {
|
|
749
|
+
writes.push({ method: 'set', path: ref.descriptor.path, data, options });
|
|
750
|
+
return batch;
|
|
751
|
+
},
|
|
752
|
+
update(ref, data) {
|
|
753
|
+
writes.push({ method: 'update', path: ref.descriptor.path, data });
|
|
754
|
+
return batch;
|
|
755
|
+
},
|
|
756
|
+
delete(ref) {
|
|
757
|
+
writes.push({ method: 'delete', path: ref.descriptor.path });
|
|
758
|
+
return batch;
|
|
759
|
+
},
|
|
760
|
+
async commit() {
|
|
761
|
+
await dataRpc(port, {
|
|
762
|
+
t: 'op',
|
|
763
|
+
id: nextId(),
|
|
764
|
+
method: 'batchCommit',
|
|
765
|
+
writes: [...writes],
|
|
766
|
+
});
|
|
767
|
+
},
|
|
768
|
+
};
|
|
769
|
+
return batch;
|
|
770
|
+
}
|
|
771
|
+
/**
|
|
772
|
+
* Maximum number of times the client will retry `updateFn` on a
|
|
773
|
+
* worker-reported conflict (`aborted`). Matches Firestore SDK default.
|
|
774
|
+
*/
|
|
775
|
+
const TXN_MAX_ATTEMPTS = 5;
|
|
776
|
+
/**
|
|
777
|
+
* Run a transaction. Mirrors `pyric/firestore`'s `runTransaction(db, fn)`.
|
|
778
|
+
*
|
|
779
|
+
* MULTI-TAB CORRECTNESS — READ-SET VALIDATION + RETRY
|
|
780
|
+
* ----------------------------------------------------
|
|
781
|
+
* A transaction spans two messages: the `txn.get` RPC (read) and the
|
|
782
|
+
* `txnCommit` RPC (commit). Between those two messages another tab may
|
|
783
|
+
* write to a doc the current tab read — a silent lost update without
|
|
784
|
+
* validation. We fix this the standard way:
|
|
785
|
+
*
|
|
786
|
+
* 1. Each `txn.get(ref)` records `{ path, data }` in a per-attempt
|
|
787
|
+
* read-set (`data` is the raw `SerializedDocData` the worker
|
|
788
|
+
* returned, or `null` if the doc was missing).
|
|
789
|
+
* 2. `txnCommit` carries both `reads` (the read-set) and `writes`.
|
|
790
|
+
* 3. The worker re-reads each doc inside a sandbox transaction, re-
|
|
791
|
+
* serializes it the same way, and compares the JSON strings.
|
|
792
|
+
* Any mismatch → `{ ok: false, error: { code: 'aborted' } }`.
|
|
793
|
+
* 4. On `aborted`, the client discards the result of `updateFn` and
|
|
794
|
+
* re-runs it with a fresh transaction object (fresh reads, empty
|
|
795
|
+
* write buffer). Up to `TXN_MAX_ATTEMPTS` attempts are made.
|
|
796
|
+
* 5. After the cap, throws an error with `.code === 'aborted'`.
|
|
797
|
+
*
|
|
798
|
+
* This matches real Firestore's behaviour: the SDK retries `updateFn`
|
|
799
|
+
* on conflict rather than surfacing the error immediately.
|
|
800
|
+
*/
|
|
801
|
+
export async function runTransaction(db, updateFn) {
|
|
802
|
+
const port = db.port;
|
|
803
|
+
for (let attempt = 0; attempt < TXN_MAX_ATTEMPTS; attempt++) {
|
|
804
|
+
// Fresh read-set and write buffer for each attempt.
|
|
805
|
+
const reads = [];
|
|
806
|
+
const writes = [];
|
|
807
|
+
const txn = {
|
|
808
|
+
async get(ref) {
|
|
809
|
+
// RPC to the worker — capture the raw result before rehydration.
|
|
810
|
+
const rawResult = await dataRpc(ref.port, {
|
|
811
|
+
t: 'op',
|
|
812
|
+
id: nextId(),
|
|
813
|
+
method: 'getDoc',
|
|
814
|
+
path: ref.descriptor.path,
|
|
815
|
+
});
|
|
816
|
+
// Record the raw serialized data (or null) in the read-set.
|
|
817
|
+
// We preserve the wire-form SerializedDocData so the worker can
|
|
818
|
+
// re-serialize the current doc and compare JSON strings.
|
|
819
|
+
reads.push({
|
|
820
|
+
path: ref.descriptor.path,
|
|
821
|
+
data: (rawResult.exists && rawResult.data) ? rawResult.data : null,
|
|
822
|
+
});
|
|
823
|
+
return makeDocSnapshot(rawResult);
|
|
824
|
+
},
|
|
825
|
+
set(ref, data, options) {
|
|
826
|
+
writes.push({ method: 'set', path: ref.descriptor.path, data, options });
|
|
827
|
+
},
|
|
828
|
+
update(ref, data) {
|
|
829
|
+
writes.push({ method: 'update', path: ref.descriptor.path, data });
|
|
830
|
+
},
|
|
831
|
+
delete(ref) {
|
|
832
|
+
writes.push({ method: 'delete', path: ref.descriptor.path });
|
|
833
|
+
},
|
|
834
|
+
};
|
|
835
|
+
const result = await updateFn(txn);
|
|
836
|
+
// Send read-set + writes to the worker for validation and commit.
|
|
837
|
+
try {
|
|
838
|
+
await dataRpc(port, {
|
|
839
|
+
t: 'op',
|
|
840
|
+
id: nextId(),
|
|
841
|
+
method: 'txnCommit',
|
|
842
|
+
reads: [...reads],
|
|
843
|
+
writes: [...writes],
|
|
844
|
+
});
|
|
845
|
+
return result;
|
|
846
|
+
}
|
|
847
|
+
catch (err) {
|
|
848
|
+
const e = err;
|
|
849
|
+
if (e.code === 'aborted') {
|
|
850
|
+
// Conflict detected — retry updateFn on the next attempt.
|
|
851
|
+
continue;
|
|
852
|
+
}
|
|
853
|
+
// Permission-denied, not-found, etc. — propagate immediately.
|
|
854
|
+
throw err;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
// Exceeded max attempts.
|
|
858
|
+
const abortErr = new Error(`Transaction failed after ${TXN_MAX_ATTEMPTS} attempts due to repeated conflicts. ` +
|
|
859
|
+
'Another tab is concurrently writing to the same documents.');
|
|
860
|
+
abortErr.code = 'aborted';
|
|
861
|
+
throw abortErr;
|
|
862
|
+
}
|
|
863
|
+
// ─── setRules ────────────────────────────────────────────────────────────
|
|
864
|
+
/**
|
|
865
|
+
* Deploy new rules to the worker's sandbox. Active onSnapshot listeners
|
|
866
|
+
* that were allowed by the old rules may start receiving error callbacks
|
|
867
|
+
* if the new rules deny them.
|
|
868
|
+
*/
|
|
869
|
+
export async function setRules(db, source) {
|
|
870
|
+
const result = await rpc(db.port, {
|
|
871
|
+
t: 'op',
|
|
872
|
+
id: nextId(),
|
|
873
|
+
method: 'setRules',
|
|
874
|
+
source,
|
|
875
|
+
});
|
|
876
|
+
return result;
|
|
877
|
+
}
|
|
878
|
+
export async function setFirestoreRules(db, source) {
|
|
879
|
+
const result = await rpc(db.port, {
|
|
880
|
+
t: 'op',
|
|
881
|
+
id: nextId(),
|
|
882
|
+
method: 'setFirestoreRules',
|
|
883
|
+
source,
|
|
884
|
+
});
|
|
885
|
+
return result;
|
|
886
|
+
}
|
|
887
|
+
export async function setDatabaseRules(db, source) {
|
|
888
|
+
const result = await rpc(db.port, {
|
|
889
|
+
t: 'op',
|
|
890
|
+
id: nextId(),
|
|
891
|
+
method: 'setDatabaseRules',
|
|
892
|
+
source,
|
|
893
|
+
});
|
|
894
|
+
return result;
|
|
895
|
+
}
|
|
896
|
+
export async function getActiveRules(db, service) {
|
|
897
|
+
return rpc(db.port, { t: 'op', id: nextId(), method: 'getActiveRules', service });
|
|
898
|
+
}
|
|
899
|
+
export async function getRulesStatus(db, service) {
|
|
900
|
+
return rpc(db.port, { t: 'op', id: nextId(), method: 'getRulesStatus', service });
|
|
901
|
+
}
|
|
902
|
+
export async function adminGetDocument(db, path) {
|
|
903
|
+
return (await rpc(db.port, { t: 'op', id: nextId(), method: 'admin.getDocument', path }));
|
|
904
|
+
}
|
|
905
|
+
export async function adminListDocuments(db, path) {
|
|
906
|
+
return (await rpc(db.port, { t: 'op', id: nextId(), method: 'admin.listDocuments', path }));
|
|
907
|
+
}
|
|
908
|
+
export async function adminSetDocument(db, path, data) {
|
|
909
|
+
await rpc(db.port, { t: 'op', id: nextId(), method: 'admin.setDocument', path, data });
|
|
910
|
+
}
|
|
911
|
+
export async function adminDeleteDocument(db, path) {
|
|
912
|
+
return (await rpc(db.port, { t: 'op', id: nextId(), method: 'admin.deleteDocument', path }));
|
|
913
|
+
}
|
|
914
|
+
export async function adminReadState(db, opts = {}) {
|
|
915
|
+
return (await rpc(db.port, {
|
|
916
|
+
t: 'op',
|
|
917
|
+
id: nextId(),
|
|
918
|
+
method: 'admin.readState',
|
|
919
|
+
...opts,
|
|
920
|
+
}));
|
|
921
|
+
}
|
|
922
|
+
// ─── RTDB shared-worker modular subset ────────────────────────────────────
|
|
923
|
+
export function rtdbGetDatabase(source, name) {
|
|
924
|
+
if (source && typeof source === 'object' && 'port' in source) {
|
|
925
|
+
return { __kind: 'client-rtdb', port: source.port };
|
|
926
|
+
}
|
|
927
|
+
const firestore = getFirestore(source ?? '/__pyric/sdk/worker.js', name);
|
|
928
|
+
return { __kind: 'client-rtdb', port: firestore.port };
|
|
929
|
+
}
|
|
930
|
+
function normalizeRtdbPath(path) {
|
|
931
|
+
const joined = (path ?? '/').split('/').filter(Boolean).join('/');
|
|
932
|
+
return joined ? `/${joined}` : '/';
|
|
933
|
+
}
|
|
934
|
+
function rtdbKey(path) {
|
|
935
|
+
const parts = path.split('/').filter(Boolean);
|
|
936
|
+
return parts.at(-1) ?? null;
|
|
937
|
+
}
|
|
938
|
+
const RTDB_PUSH_CHARS = '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz';
|
|
939
|
+
let lastRtdbPushTime = 0;
|
|
940
|
+
const lastRtdbRandChars = new Array(12).fill(0);
|
|
941
|
+
function generateRtdbPushId(now = Date.now()) {
|
|
942
|
+
const duplicateTime = now === lastRtdbPushTime;
|
|
943
|
+
lastRtdbPushTime = now;
|
|
944
|
+
const timeStampChars = new Array(8);
|
|
945
|
+
let ts = now;
|
|
946
|
+
for (let i = 7; i >= 0; i--) {
|
|
947
|
+
timeStampChars[i] = RTDB_PUSH_CHARS.charAt(ts % 64);
|
|
948
|
+
ts = Math.floor(ts / 64);
|
|
949
|
+
}
|
|
950
|
+
if (ts !== 0)
|
|
951
|
+
throw new Error('RTDB push-id: timestamp overflow.');
|
|
952
|
+
if (!duplicateTime) {
|
|
953
|
+
for (let i = 0; i < 12; i++)
|
|
954
|
+
lastRtdbRandChars[i] = Math.floor(Math.random() * 64);
|
|
955
|
+
}
|
|
956
|
+
else {
|
|
957
|
+
let i;
|
|
958
|
+
for (i = 11; i >= 0 && lastRtdbRandChars[i] === 63; i--)
|
|
959
|
+
lastRtdbRandChars[i] = 0;
|
|
960
|
+
if (i < 0) {
|
|
961
|
+
for (let j = 0; j < 12; j++)
|
|
962
|
+
lastRtdbRandChars[j] = Math.floor(Math.random() * 64);
|
|
963
|
+
}
|
|
964
|
+
else {
|
|
965
|
+
lastRtdbRandChars[i] = (lastRtdbRandChars[i] ?? 0) + 1;
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
let id = timeStampChars.join('');
|
|
969
|
+
for (let i = 0; i < 12; i++)
|
|
970
|
+
id += RTDB_PUSH_CHARS.charAt(lastRtdbRandChars[i]);
|
|
971
|
+
return id;
|
|
972
|
+
}
|
|
973
|
+
function makeRtdbRef(port, path) {
|
|
974
|
+
const normalized = normalizeRtdbPath(path);
|
|
975
|
+
const parts = normalized.split('/').filter(Boolean);
|
|
976
|
+
const parentPath = parts.length > 0 ? `/${parts.slice(0, -1).join('/')}` : '/';
|
|
977
|
+
const self = {
|
|
978
|
+
__kind: 'rtdb-ref',
|
|
979
|
+
port,
|
|
980
|
+
path: normalized,
|
|
981
|
+
key: rtdbKey(normalized),
|
|
982
|
+
get parent() {
|
|
983
|
+
return normalized === '/' ? null : makeRtdbRef(port, parentPath);
|
|
984
|
+
},
|
|
985
|
+
get root() {
|
|
986
|
+
return makeRtdbRef(port, '/');
|
|
987
|
+
},
|
|
988
|
+
toString() {
|
|
989
|
+
return `worker://rtdb${normalized}`;
|
|
990
|
+
},
|
|
991
|
+
};
|
|
992
|
+
return self;
|
|
993
|
+
}
|
|
994
|
+
export function rtdbRef(db, path) {
|
|
995
|
+
return makeRtdbRef(db.port, path ?? '/');
|
|
996
|
+
}
|
|
997
|
+
export function rtdbChild(parent, path) {
|
|
998
|
+
return makeRtdbRef(parent.port, `${parent.path}/${path}`);
|
|
999
|
+
}
|
|
1000
|
+
function valueAt(root, path) {
|
|
1001
|
+
let current = root;
|
|
1002
|
+
for (const segment of path.split('/').filter(Boolean)) {
|
|
1003
|
+
if (current === null || typeof current !== 'object')
|
|
1004
|
+
return null;
|
|
1005
|
+
current = current[segment];
|
|
1006
|
+
}
|
|
1007
|
+
return current === undefined ? null : current;
|
|
1008
|
+
}
|
|
1009
|
+
function makeRtdbSnapshot(refHandle, value, exists) {
|
|
1010
|
+
const childValue = (path) => valueAt(value, path);
|
|
1011
|
+
const size = value && typeof value === 'object' && !Array.isArray(value)
|
|
1012
|
+
? Object.keys(value).length
|
|
1013
|
+
: 0;
|
|
1014
|
+
const snapshot = {
|
|
1015
|
+
key: refHandle.key,
|
|
1016
|
+
size,
|
|
1017
|
+
exists: () => exists ?? (value !== null && value !== undefined),
|
|
1018
|
+
val: () => value ?? null,
|
|
1019
|
+
child: (path) => makeRtdbSnapshot(rtdbChild(refHandle, path), childValue(path)),
|
|
1020
|
+
hasChild: (path) => childValue(path) !== null && childValue(path) !== undefined,
|
|
1021
|
+
hasChildren: () => size > 0,
|
|
1022
|
+
exportVal: () => value ?? null,
|
|
1023
|
+
toJSON: () => value ?? null,
|
|
1024
|
+
forEach: (cb) => {
|
|
1025
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
1026
|
+
return false;
|
|
1027
|
+
for (const [key, childVal] of Object.entries(value)) {
|
|
1028
|
+
if (cb(makeRtdbSnapshot(rtdbChild(refHandle, key), childVal)) === true)
|
|
1029
|
+
return true;
|
|
1030
|
+
}
|
|
1031
|
+
return false;
|
|
1032
|
+
},
|
|
1033
|
+
ref: refHandle,
|
|
1034
|
+
};
|
|
1035
|
+
return snapshot;
|
|
1036
|
+
}
|
|
1037
|
+
function hydrateRtdbSnapshot(refHandle, wire) {
|
|
1038
|
+
const payload = wire;
|
|
1039
|
+
return makeRtdbSnapshot(refHandle, payload.value ?? null, payload.exists);
|
|
1040
|
+
}
|
|
1041
|
+
export async function rtdbGet(r) {
|
|
1042
|
+
return hydrateRtdbSnapshot(r, await dataRpc(r.port, { t: 'op', id: nextId(), method: 'rtdb.get', path: r.path }));
|
|
1043
|
+
}
|
|
1044
|
+
export async function adminReadRtdbState(db) {
|
|
1045
|
+
return rpc(db.port, { t: 'op', id: nextId(), method: 'rtdb.adminSnapshot' });
|
|
1046
|
+
}
|
|
1047
|
+
export async function adminSetRtdbValue(db, path, value) {
|
|
1048
|
+
await rpc(db.port, {
|
|
1049
|
+
t: 'op',
|
|
1050
|
+
id: nextId(),
|
|
1051
|
+
method: 'rtdb.set',
|
|
1052
|
+
path,
|
|
1053
|
+
value,
|
|
1054
|
+
actAs: { mode: 'admin' },
|
|
1055
|
+
});
|
|
1056
|
+
}
|
|
1057
|
+
export async function adminUpdateRtdbValue(db, path, values) {
|
|
1058
|
+
await rpc(db.port, {
|
|
1059
|
+
t: 'op',
|
|
1060
|
+
id: nextId(),
|
|
1061
|
+
method: 'rtdb.update',
|
|
1062
|
+
path,
|
|
1063
|
+
values,
|
|
1064
|
+
actAs: { mode: 'admin' },
|
|
1065
|
+
});
|
|
1066
|
+
}
|
|
1067
|
+
export async function adminDeleteRtdbValue(db, path) {
|
|
1068
|
+
await rpc(db.port, {
|
|
1069
|
+
t: 'op',
|
|
1070
|
+
id: nextId(),
|
|
1071
|
+
method: 'rtdb.remove',
|
|
1072
|
+
path,
|
|
1073
|
+
actAs: { mode: 'admin' },
|
|
1074
|
+
});
|
|
1075
|
+
}
|
|
1076
|
+
/**
|
|
1077
|
+
* Subscribe to the raw value at an RTDB path with the ADMIN lens (Pyric Studio
|
|
1078
|
+
* data viewer). Rides the same `{service:'rtdb'}` value-subscription channel as
|
|
1079
|
+
* `rtdbOnValue`, but pins `actAs: {mode:'admin'}` per-sub instead of following
|
|
1080
|
+
* the module default lens, so Studio's viewer stays admin (PRINCIPLES M3) while
|
|
1081
|
+
* the page's own listeners keep their session semantics.
|
|
1082
|
+
*
|
|
1083
|
+
* `next` receives the plain JSON value at `path` (`null` when absent) on
|
|
1084
|
+
* subscribe and again after every write that changes the subtree.
|
|
1085
|
+
*/
|
|
1086
|
+
export function adminSubscribeRtdbValue(db, path, next, error) {
|
|
1087
|
+
const subId = nextSubId();
|
|
1088
|
+
_snapSubs.set(subId, {
|
|
1089
|
+
next: (wire) => next(wire?.value ?? null),
|
|
1090
|
+
error,
|
|
1091
|
+
});
|
|
1092
|
+
db.port.postMessage(stampIssuer({
|
|
1093
|
+
t: 'sub',
|
|
1094
|
+
subId,
|
|
1095
|
+
target: { service: 'rtdb', path: normalizeRtdbPath(path) },
|
|
1096
|
+
actAs: { mode: 'admin' },
|
|
1097
|
+
}));
|
|
1098
|
+
return () => {
|
|
1099
|
+
_snapSubs.delete(subId);
|
|
1100
|
+
db.port.postMessage({ t: 'unsub', subId });
|
|
1101
|
+
};
|
|
1102
|
+
}
|
|
1103
|
+
export async function rtdbSet(r, value) {
|
|
1104
|
+
await dataRpc(r.port, { t: 'op', id: nextId(), method: 'rtdb.set', path: r.path, value });
|
|
1105
|
+
}
|
|
1106
|
+
export async function rtdbUpdate(r, values) {
|
|
1107
|
+
await dataRpc(r.port, { t: 'op', id: nextId(), method: 'rtdb.update', path: r.path, values });
|
|
1108
|
+
}
|
|
1109
|
+
export async function rtdbRemove(r) {
|
|
1110
|
+
await dataRpc(r.port, { t: 'op', id: nextId(), method: 'rtdb.remove', path: r.path });
|
|
1111
|
+
}
|
|
1112
|
+
export function rtdbPush(r, value) {
|
|
1113
|
+
const key = generateRtdbPushId();
|
|
1114
|
+
const pushed = makeRtdbRef(r.port, `${r.path}/${key}`);
|
|
1115
|
+
const settledRef = makeRtdbRef(r.port, pushed.path);
|
|
1116
|
+
const promise = dataRpc(r.port, { t: 'op', id: nextId(), method: 'rtdb.push', path: r.path, key, value })
|
|
1117
|
+
.then(() => settledRef);
|
|
1118
|
+
return Object.assign(pushed, {
|
|
1119
|
+
then: promise.then.bind(promise),
|
|
1120
|
+
catch: promise.catch.bind(promise),
|
|
1121
|
+
});
|
|
1122
|
+
}
|
|
1123
|
+
export function rtdbOnValue(r, next, error) {
|
|
1124
|
+
const subId = nextSubId();
|
|
1125
|
+
_snapSubs.set(subId, {
|
|
1126
|
+
next: (wire) => next(hydrateRtdbSnapshot(r, wire)),
|
|
1127
|
+
error,
|
|
1128
|
+
});
|
|
1129
|
+
const msg = _defaultLens
|
|
1130
|
+
? { t: 'sub', subId, target: { service: 'rtdb', path: r.path }, actAs: _defaultLens }
|
|
1131
|
+
: { t: 'sub', subId, target: { service: 'rtdb', path: r.path } };
|
|
1132
|
+
r.port.postMessage(stampIssuer(msg));
|
|
1133
|
+
return () => {
|
|
1134
|
+
_snapSubs.delete(subId);
|
|
1135
|
+
r.port.postMessage({ t: 'unsub', subId });
|
|
1136
|
+
};
|
|
1137
|
+
}
|
|
1138
|
+
export function rtdbOff(_r, _eventType, _callback) {
|
|
1139
|
+
// Firebase's `off` is callback-specific. The worker bridge exposes unsubscribe
|
|
1140
|
+
// functions from `onValue`; this no-op preserves common app code that calls it
|
|
1141
|
+
// defensively during cleanup.
|
|
1142
|
+
}
|
|
1143
|
+
export function rtdbServerTimestamp() {
|
|
1144
|
+
return { __rtdbSentinel: 'serverTimestamp' };
|
|
1145
|
+
}
|
|
1146
|
+
export function rtdbConnectDatabaseEmulator() {
|
|
1147
|
+
// Shared worker sandbox is already local.
|
|
1148
|
+
}
|
|
1149
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
1150
|
+
// EVENT STREAM (Pyric Studio keystone — onEvent/history over the port)
|
|
1151
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
1152
|
+
//
|
|
1153
|
+
// Surfaces the worker sandbox's unified cross-service event stream to the page.
|
|
1154
|
+
// `subscribeEvents(db, cb)` registers a stream sub: the worker first delivers
|
|
1155
|
+
// `sandbox.history()` as one batch, then streams each live `SandboxEvent` as a
|
|
1156
|
+
// single-element batch. `eventHistory(db)` is a one-shot history fetch (a fresh
|
|
1157
|
+
// short-lived sub) for consumers that want a snapshot without staying live.
|
|
1158
|
+
//
|
|
1159
|
+
// These mirror `sandbox.onEvent(cb)` / `sandbox.history()` so a consumer can
|
|
1160
|
+
// adapt them into the same `{ onEvent, history }`-shaped source the in-process
|
|
1161
|
+
// sandbox exposes (e.g. Studio's `feedFromSandboxLike`).
|
|
1162
|
+
/**
|
|
1163
|
+
* Subscribe to the worker sandbox's unified event stream. The callback fires
|
|
1164
|
+
* with each delivered BATCH of events — the FIRST call carries the initial
|
|
1165
|
+
* `history()` snapshot (possibly empty), each subsequent call carries one live
|
|
1166
|
+
* event. Returns an unsubscribe that deregisters on the worker.
|
|
1167
|
+
*
|
|
1168
|
+
* This is the live counterpart to `sandbox.onEvent` + an initial `history()`
|
|
1169
|
+
* fold, collapsed into one subscription so a late subscriber never misses the
|
|
1170
|
+
* backlog.
|
|
1171
|
+
*/
|
|
1172
|
+
export function subscribeEvents(db, callback) {
|
|
1173
|
+
const subId = nextSubId();
|
|
1174
|
+
const port = db.port;
|
|
1175
|
+
_eventSubs.set(subId, callback);
|
|
1176
|
+
port.postMessage({ t: 'sub', subId, target: 'events' });
|
|
1177
|
+
return () => {
|
|
1178
|
+
_eventSubs.delete(subId);
|
|
1179
|
+
port.postMessage({ t: 'unsub', subId });
|
|
1180
|
+
};
|
|
1181
|
+
}
|
|
1182
|
+
/**
|
|
1183
|
+
* Fetch the worker sandbox's event history as a one-shot snapshot (every event
|
|
1184
|
+
* so far). Opens a transient stream sub, resolves with the initial history
|
|
1185
|
+
* batch, and tears the sub down immediately — so it never holds a live
|
|
1186
|
+
* subscription. Useful for a late, snapshot-only consumer.
|
|
1187
|
+
*/
|
|
1188
|
+
export function eventHistory(db) {
|
|
1189
|
+
return new Promise((resolve) => {
|
|
1190
|
+
const unsub = subscribeEvents(db, (events) => {
|
|
1191
|
+
// The first delivery is the history snapshot; resolve + unsubscribe.
|
|
1192
|
+
unsub();
|
|
1193
|
+
resolve(events);
|
|
1194
|
+
});
|
|
1195
|
+
});
|
|
1196
|
+
}
|
|
1197
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
1198
|
+
// RUNTIME CONFIRM-POLICY (Pyric Studio F3 — permission dial)
|
|
1199
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
1200
|
+
//
|
|
1201
|
+
// The permission dial pushes a `PolicyRequest` describing the governance the
|
|
1202
|
+
// served sandbox/agent runtime should honour. `setPolicy` stores it on the
|
|
1203
|
+
// worker (the worker-side store); `getPolicy` reads the active one back (null
|
|
1204
|
+
// until the dial set one), so a freshly-connecting Studio tab hydrates the dial.
|
|
1205
|
+
//
|
|
1206
|
+
// HONEST LIMITATION (re-stated where the seam is used): this updates the
|
|
1207
|
+
// WORKER-SIDE store, NOT a running bridge process's confirm handler (built once
|
|
1208
|
+
// at bridge startup, in a separate node process). Pushing live to a running
|
|
1209
|
+
// bridge needs a separate transport. See `PolicyRequest` in protocol.ts.
|
|
1210
|
+
/** Push the active runtime confirm-policy to the worker (Pyric Studio F3). */
|
|
1211
|
+
export async function setPolicy(db, policy) {
|
|
1212
|
+
await rpc(db.port, { t: 'op', id: nextId(), method: 'setPolicy', policy });
|
|
1213
|
+
}
|
|
1214
|
+
/** Read the active runtime confirm-policy back (null until the dial set one). */
|
|
1215
|
+
export async function getPolicy(db) {
|
|
1216
|
+
return (await rpc(db.port, { t: 'op', id: nextId(), method: 'getPolicy' }));
|
|
1217
|
+
}
|
|
1218
|
+
/**
|
|
1219
|
+
* Export the current sandbox snapshot (Pyric Studio rules re-run). Studio forks
|
|
1220
|
+
* it locally to test a denied op against edited rules or re-issue it as the
|
|
1221
|
+
* attempting user, on a throwaway branch (no live mutation).
|
|
1222
|
+
*/
|
|
1223
|
+
export async function getSnapshot(db) {
|
|
1224
|
+
return (await rpc(db.port, { t: 'op', id: nextId(), method: 'getSnapshot' }));
|
|
1225
|
+
}
|
|
1226
|
+
/** Hidden per-`ClientUser` port handle so the top-level `updateProfile(user, …)`
|
|
1227
|
+
* free function can RPC without an `auth` handle in scope (mirrors
|
|
1228
|
+
* `firebase/auth`'s user-only signature). Non-enumerable — never serialized. */
|
|
1229
|
+
const CLIENT_USER_PORT = Symbol('pyric.clientUser.port');
|
|
1230
|
+
/** Build a token-capable ClientUser from a wire SerializedUser. */
|
|
1231
|
+
function makeClientUser(port, raw) {
|
|
1232
|
+
const user = {
|
|
1233
|
+
uid: raw.uid,
|
|
1234
|
+
email: raw.email,
|
|
1235
|
+
emailVerified: raw.emailVerified,
|
|
1236
|
+
displayName: raw.displayName,
|
|
1237
|
+
photoURL: raw.photoURL,
|
|
1238
|
+
phoneNumber: raw.phoneNumber,
|
|
1239
|
+
isAnonymous: raw.isAnonymous,
|
|
1240
|
+
providerId: raw.providerId,
|
|
1241
|
+
providerData: raw.providerData,
|
|
1242
|
+
async getIdToken(forceRefresh) {
|
|
1243
|
+
return (await rpc(port, {
|
|
1244
|
+
t: 'op', id: nextId(), method: 'auth.getIdToken', forceRefresh,
|
|
1245
|
+
}));
|
|
1246
|
+
},
|
|
1247
|
+
async getIdTokenResult(forceRefresh) {
|
|
1248
|
+
return (await rpc(port, {
|
|
1249
|
+
t: 'op', id: nextId(), method: 'auth.getIdTokenResult', forceRefresh,
|
|
1250
|
+
}));
|
|
1251
|
+
},
|
|
1252
|
+
};
|
|
1253
|
+
Object.defineProperty(user, CLIENT_USER_PORT, { value: port, enumerable: false });
|
|
1254
|
+
return user;
|
|
1255
|
+
}
|
|
1256
|
+
/** Convert a wire SerializedUser|null to a ClientUser|null. */
|
|
1257
|
+
function toClientUser(port, raw) {
|
|
1258
|
+
return raw ? makeClientUser(port, raw) : null;
|
|
1259
|
+
}
|
|
1260
|
+
/**
|
|
1261
|
+
* Get the worker-backed Auth handle.
|
|
1262
|
+
*
|
|
1263
|
+
* Mirrors `pyric/auth`'s `getAuth(sandbox)` / `firebase/auth`'s
|
|
1264
|
+
* `getAuth(app)` — but the input is either an existing `ClientDb` (reusing
|
|
1265
|
+
* its port, the common case in serve where Firestore + auth share one
|
|
1266
|
+
* worker) or a worker URL (standalone).
|
|
1267
|
+
*
|
|
1268
|
+
* The returned handle seeds its `currentUser` mirror by opening an internal
|
|
1269
|
+
* authState subscription that keeps it live across tabs.
|
|
1270
|
+
*/
|
|
1271
|
+
export function getAuth(source, name) {
|
|
1272
|
+
let port;
|
|
1273
|
+
if (typeof source === 'object' && '__kind' in source && source.__kind === 'client-db') {
|
|
1274
|
+
port = source.port;
|
|
1275
|
+
}
|
|
1276
|
+
else {
|
|
1277
|
+
if (typeof SharedWorker === 'undefined') {
|
|
1278
|
+
throw new Error('SharedWorker is not available. ' +
|
|
1279
|
+
'Open this page over http:// (not file://) and use a supported browser ' +
|
|
1280
|
+
'(Chrome 4+, Firefox 29+, Safari 16.4+).');
|
|
1281
|
+
}
|
|
1282
|
+
const worker = new SharedWorker(source, {
|
|
1283
|
+
type: 'classic',
|
|
1284
|
+
name: name ?? 'pyric-shared-worker',
|
|
1285
|
+
});
|
|
1286
|
+
port = worker.port;
|
|
1287
|
+
port.start();
|
|
1288
|
+
wirePort(port);
|
|
1289
|
+
}
|
|
1290
|
+
const auth = { __kind: 'client-auth', port, currentUser: null };
|
|
1291
|
+
// Internal authState subscription keeps `auth.currentUser` live. Per-port
|
|
1292
|
+
// sessions (#754): only THIS port's sign-ins/outs (and its session restore)
|
|
1293
|
+
// fire here — another tab's sign-in is another user, not an update to us.
|
|
1294
|
+
const subId = nextSubId();
|
|
1295
|
+
_snapSubs.set(subId, {
|
|
1296
|
+
next: (raw) => {
|
|
1297
|
+
auth.currentUser = toClientUser(port, raw);
|
|
1298
|
+
},
|
|
1299
|
+
});
|
|
1300
|
+
port.postMessage({ t: 'sub', subId, target: 'authState' });
|
|
1301
|
+
return auth;
|
|
1302
|
+
}
|
|
1303
|
+
/**
|
|
1304
|
+
* Connect to the auth emulator. No-op shim over the worker: the worker's
|
|
1305
|
+
* sandbox IS the emulator-equivalent backend, so there's nothing to point at.
|
|
1306
|
+
* Present for surface parity so app code that calls it doesn't break.
|
|
1307
|
+
*/
|
|
1308
|
+
export function connectAuthEmulator(_auth, _url, _options) {
|
|
1309
|
+
// Intentional no-op — the worker's sandbox is the local auth backend.
|
|
1310
|
+
}
|
|
1311
|
+
// ─── Sign-in / out / create (RPC) ─────────────────────────────────────────
|
|
1312
|
+
export async function createUserWithEmailAndPassword(auth, email, password) {
|
|
1313
|
+
const raw = (await rpc(auth.port, {
|
|
1314
|
+
t: 'op', id: nextId(), method: 'auth.createUser', email, password,
|
|
1315
|
+
}));
|
|
1316
|
+
return hydrateCred(auth, raw);
|
|
1317
|
+
}
|
|
1318
|
+
// ─── Admin user-DB ops (Pyric Studio data browse) ─────────────────────────
|
|
1319
|
+
// Mirror `pyric/auth`'s `sandbox.{listUsers,createUser,updateUser,deleteUser,
|
|
1320
|
+
// clearUsers}` over the port. No lens (admin control surface), so bare `rpc`.
|
|
1321
|
+
export async function listUsers(auth) {
|
|
1322
|
+
return (await rpc(auth.port, {
|
|
1323
|
+
t: 'op', id: nextId(), method: 'auth.listUsers',
|
|
1324
|
+
}));
|
|
1325
|
+
}
|
|
1326
|
+
export async function adminCreateUser(auth, request) {
|
|
1327
|
+
return (await rpc(auth.port, {
|
|
1328
|
+
t: 'op', id: nextId(), method: 'auth.adminCreateUser',
|
|
1329
|
+
request: request,
|
|
1330
|
+
}));
|
|
1331
|
+
}
|
|
1332
|
+
export async function adminUpdateUser(auth, uid, request) {
|
|
1333
|
+
return (await rpc(auth.port, {
|
|
1334
|
+
t: 'op', id: nextId(), method: 'auth.adminUpdateUser', uid,
|
|
1335
|
+
request: request,
|
|
1336
|
+
}));
|
|
1337
|
+
}
|
|
1338
|
+
export async function adminDeleteUser(auth, uid) {
|
|
1339
|
+
await rpc(auth.port, { t: 'op', id: nextId(), method: 'auth.adminDeleteUser', uid });
|
|
1340
|
+
}
|
|
1341
|
+
export async function adminClearUsers(auth) {
|
|
1342
|
+
await rpc(auth.port, { t: 'op', id: nextId(), method: 'auth.adminClearUsers' });
|
|
1343
|
+
}
|
|
1344
|
+
// ─── Sign-in provider config (Pyric Studio S-AUTH) ────────────────────────
|
|
1345
|
+
// Mirror `pyric/auth`'s `sandbox.{getAuthProviderConfig,setAuthProviderConfig}`
|
|
1346
|
+
// over the port. No dedicated subscription: `setProviderConfig` fires a
|
|
1347
|
+
// `provider_config_update` sandbox event, so a caller re-reads via
|
|
1348
|
+
// `getProviderConfig` on the SAME event feed `listUsers` callers already
|
|
1349
|
+
// subscribe to (see `worker-live.ts`'s `subscribeUsers`).
|
|
1350
|
+
export async function getProviderConfig(auth) {
|
|
1351
|
+
return (await rpc(auth.port, {
|
|
1352
|
+
t: 'op', id: nextId(), method: 'auth.getProviderConfig',
|
|
1353
|
+
}));
|
|
1354
|
+
}
|
|
1355
|
+
export async function setProviderConfig(auth, providerId, enabled) {
|
|
1356
|
+
await rpc(auth.port, {
|
|
1357
|
+
t: 'op', id: nextId(), method: 'auth.setProviderConfig', providerId, enabled,
|
|
1358
|
+
});
|
|
1359
|
+
}
|
|
1360
|
+
export async function signInWithEmailAndPassword(auth, email, password) {
|
|
1361
|
+
const raw = (await rpc(auth.port, {
|
|
1362
|
+
t: 'op', id: nextId(), method: 'auth.signInEmail', email, password,
|
|
1363
|
+
}));
|
|
1364
|
+
return hydrateCred(auth, raw);
|
|
1365
|
+
}
|
|
1366
|
+
export async function signInAnonymously(auth) {
|
|
1367
|
+
const raw = (await rpc(auth.port, {
|
|
1368
|
+
t: 'op', id: nextId(), method: 'auth.signInAnonymously',
|
|
1369
|
+
}));
|
|
1370
|
+
return hydrateCred(auth, raw);
|
|
1371
|
+
}
|
|
1372
|
+
export async function signOut(auth) {
|
|
1373
|
+
await rpc(auth.port, { t: 'op', id: nextId(), method: 'auth.signOut' });
|
|
1374
|
+
// The authState stream will also clear the mirror; set eagerly so a
|
|
1375
|
+
// synchronous read right after `await signOut()` reflects the change.
|
|
1376
|
+
auth.currentUser = null;
|
|
1377
|
+
}
|
|
1378
|
+
/**
|
|
1379
|
+
* Bridge a provider identity resolved IN-PAGE to the worker (the provider
|
|
1380
|
+
* sign-in seam). The entry adapter's worker-path `signInWithPopup`/
|
|
1381
|
+
* `signInWithRedirect` runs the in-page `AuthFlowResolver` (which can't cross
|
|
1382
|
+
* the worker port), then calls this with the picked identity; the worker seeds
|
|
1383
|
+
* it + signs it in, returning a worker-backed credential. The mirror updates
|
|
1384
|
+
* eagerly (like the email/anon paths) so a synchronous `auth.currentUser`
|
|
1385
|
+
* read right after the await reflects the new user.
|
|
1386
|
+
*/
|
|
1387
|
+
export async function acceptProviderCredential(auth, identity) {
|
|
1388
|
+
const raw = (await rpc(auth.port, {
|
|
1389
|
+
t: 'op', id: nextId(), method: 'auth.acceptIdentity', identity,
|
|
1390
|
+
}));
|
|
1391
|
+
return hydrateCred(auth, raw);
|
|
1392
|
+
}
|
|
1393
|
+
/**
|
|
1394
|
+
* Re-establish THIS PORT's session for an existing identity (#754) — the
|
|
1395
|
+
* per-tab reload restore. The page persists its uid in web storage
|
|
1396
|
+
* (SessionStore); runtime.ts calls this at boot BEFORE app code runs. Soft:
|
|
1397
|
+
* returns null (and leaves the port signed out) when the uid no longer
|
|
1398
|
+
* resolves, so a stale record never throws.
|
|
1399
|
+
*/
|
|
1400
|
+
export async function restorePortSession(auth, uid) {
|
|
1401
|
+
const raw = (await rpc(auth.port, {
|
|
1402
|
+
t: 'op', id: nextId(), method: 'auth.restorePortSession', uid,
|
|
1403
|
+
}));
|
|
1404
|
+
const user = toClientUser(auth.port, raw);
|
|
1405
|
+
if (user)
|
|
1406
|
+
auth.currentUser = user;
|
|
1407
|
+
return user;
|
|
1408
|
+
}
|
|
1409
|
+
function hydrateCred(auth, raw) {
|
|
1410
|
+
const user = makeClientUser(auth.port, raw.user);
|
|
1411
|
+
// Eagerly update the mirror so `auth.currentUser` is correct immediately
|
|
1412
|
+
// after the await, before the broadcast stream lands.
|
|
1413
|
+
auth.currentUser = user;
|
|
1414
|
+
return { user, providerId: raw.providerId, operationType: raw.operationType };
|
|
1415
|
+
}
|
|
1416
|
+
// ─── Persistence ──────────────────────────────────────────────────────────
|
|
1417
|
+
/** Persistence markers — mirror `firebase/auth` / `pyric/auth`. */
|
|
1418
|
+
export const inMemoryPersistence = { type: 'NONE' };
|
|
1419
|
+
export const browserSessionPersistence = { type: 'SESSION' };
|
|
1420
|
+
export const browserLocalPersistence = { type: 'LOCAL' };
|
|
1421
|
+
/**
|
|
1422
|
+
* Record the session-persistence mode on the worker (surface parity). The
|
|
1423
|
+
* effective persistence is CLIENT-side (#754): the entry adapter mirrors the
|
|
1424
|
+
* mode into the page's SessionStore, which decides where — or whether — this
|
|
1425
|
+
* tab's session uid is stored for reload restore.
|
|
1426
|
+
*/
|
|
1427
|
+
export async function setPersistence(auth, persistence) {
|
|
1428
|
+
await rpc(auth.port, {
|
|
1429
|
+
t: 'op', id: nextId(), method: 'auth.setPersistence', mode: persistence.type,
|
|
1430
|
+
});
|
|
1431
|
+
}
|
|
1432
|
+
// ─── Observers (streaming subs) ────────────────────────────────────────────
|
|
1433
|
+
/**
|
|
1434
|
+
* Subscribe to auth-state changes. Mirrors `firebase/auth`'s
|
|
1435
|
+
* `onAuthStateChanged`. Fires immediately with THIS PORT's current session,
|
|
1436
|
+
* then on every change to it (#754: sessions are per-port — another tab's
|
|
1437
|
+
* sign-in is a different user, not an update to this one). Updates the
|
|
1438
|
+
* handle's `currentUser` mirror before invoking the callback.
|
|
1439
|
+
*/
|
|
1440
|
+
export function onAuthStateChanged(auth, callback) {
|
|
1441
|
+
return openAuthSub(auth, 'authState', callback);
|
|
1442
|
+
}
|
|
1443
|
+
/**
|
|
1444
|
+
* Subscribe to ID-token changes. Mirrors `firebase/auth`'s
|
|
1445
|
+
* `onIdTokenChanged` — fires on THIS PORT's identity transitions (per-port
|
|
1446
|
+
* sessions, #754).
|
|
1447
|
+
*/
|
|
1448
|
+
export function onIdTokenChanged(auth, callback) {
|
|
1449
|
+
return openAuthSub(auth, 'idToken', callback);
|
|
1450
|
+
}
|
|
1451
|
+
function openAuthSub(auth, target, callback) {
|
|
1452
|
+
const subId = nextSubId();
|
|
1453
|
+
const port = auth.port;
|
|
1454
|
+
_snapSubs.set(subId, {
|
|
1455
|
+
next: (raw) => {
|
|
1456
|
+
const user = toClientUser(port, raw);
|
|
1457
|
+
auth.currentUser = user;
|
|
1458
|
+
callback(user);
|
|
1459
|
+
},
|
|
1460
|
+
});
|
|
1461
|
+
port.postMessage({ t: 'sub', subId, target });
|
|
1462
|
+
return () => {
|
|
1463
|
+
_snapSubs.delete(subId);
|
|
1464
|
+
port.postMessage({ t: 'unsub', subId });
|
|
1465
|
+
};
|
|
1466
|
+
}
|
|
1467
|
+
// ─── Token accessors (top-level mirrors) ──────────────────────────────────
|
|
1468
|
+
/** Top-level mirror of `firebase/auth`'s `getIdToken(user)`. */
|
|
1469
|
+
export async function getIdToken(user, forceRefresh) {
|
|
1470
|
+
return user.getIdToken(forceRefresh);
|
|
1471
|
+
}
|
|
1472
|
+
/** Top-level mirror of `firebase/auth`'s `getIdTokenResult(user)`. */
|
|
1473
|
+
export async function getIdTokenResult(user, forceRefresh) {
|
|
1474
|
+
return user.getIdTokenResult(forceRefresh);
|
|
1475
|
+
}
|
|
1476
|
+
/**
|
|
1477
|
+
* Top-level mirror of `firebase/auth`'s `updateProfile(user, profile)` over
|
|
1478
|
+
* the worker. RPCs `auth.updateProfile` for THIS PORT's session (the worker
|
|
1479
|
+
* owns the real `User`), then mutates the passed `user` mirror in place with
|
|
1480
|
+
* the returned fields so a synchronous read right after the await is
|
|
1481
|
+
* consistent. `null` clears a field; an absent field is left untouched.
|
|
1482
|
+
*
|
|
1483
|
+
* The port is recovered from the hidden {@link CLIENT_USER_PORT} handle stamped
|
|
1484
|
+
* on every `ClientUser`, so this works without an `auth` handle in scope.
|
|
1485
|
+
*/
|
|
1486
|
+
export async function updateProfile(user, profile) {
|
|
1487
|
+
const port = user[CLIENT_USER_PORT];
|
|
1488
|
+
if (!port) {
|
|
1489
|
+
const err = new Error('updateProfile: unrecognized user — was it produced by a worker-path sign-in?');
|
|
1490
|
+
err.code = 'auth/invalid-user-token';
|
|
1491
|
+
throw err;
|
|
1492
|
+
}
|
|
1493
|
+
const raw = (await rpc(port, {
|
|
1494
|
+
t: 'op', id: nextId(), method: 'auth.updateProfile',
|
|
1495
|
+
displayName: profile.displayName, photoURL: profile.photoURL,
|
|
1496
|
+
}));
|
|
1497
|
+
// Mutate the passed mirror in place (readonly at the type level, plain data
|
|
1498
|
+
// at runtime) so held references reflect the change immediately.
|
|
1499
|
+
const mutable = user;
|
|
1500
|
+
mutable.displayName = raw.displayName;
|
|
1501
|
+
mutable.photoURL = raw.photoURL;
|
|
1502
|
+
mutable.providerData = raw.providerData;
|
|
1503
|
+
}
|
|
1504
|
+
// ─── Provider flows — NOT supported over the worker yet ───────────────────
|
|
1505
|
+
/**
|
|
1506
|
+
* Provider sign-in (`signInWithCredential`, `signInWithPopup`,
|
|
1507
|
+
* `signInWithRedirect`) needs the AuthFlowResolver, which lives in-page and
|
|
1508
|
+
* can't cross the worker port. NOT SUPPORTED over the SharedWorker in v1 —
|
|
1509
|
+
* a clear error rather than silent breakage. Tracked as a Phase 2 follow-up:
|
|
1510
|
+
* thread the resolver through, or run provider flows in-page and hand the
|
|
1511
|
+
* resulting credential to the worker.
|
|
1512
|
+
*/
|
|
1513
|
+
export function signInWithCredential() {
|
|
1514
|
+
return Promise.reject(makeUnsupported('signInWithCredential'));
|
|
1515
|
+
}
|
|
1516
|
+
function makeUnsupported(api) {
|
|
1517
|
+
const err = new Error(`${api} is not supported over the SharedWorker yet (provider flows need ` +
|
|
1518
|
+
'the in-page AuthFlowResolver). Follow-up: thread the resolver through or ' +
|
|
1519
|
+
'run the flow in-page and hand the credential to the worker.');
|
|
1520
|
+
err.code = 'auth/operation-not-supported-in-this-environment';
|
|
1521
|
+
return err;
|
|
1522
|
+
}
|
|
1523
|
+
/** Strip leading/trailing slashes (the worker keyspace uses bare paths). */
|
|
1524
|
+
function normalizeStorageRefPath(path) {
|
|
1525
|
+
return path.replace(/^\/+|\/+$/g, '');
|
|
1526
|
+
}
|
|
1527
|
+
/**
|
|
1528
|
+
* Get the worker-backed Storage handle. Like `getAuth`, accepts an existing
|
|
1529
|
+
* `ClientDb` (reusing its port) or a worker URL (standalone).
|
|
1530
|
+
*/
|
|
1531
|
+
export function getStorage(source, name) {
|
|
1532
|
+
let port;
|
|
1533
|
+
if (typeof source === 'object' && '__kind' in source && source.__kind === 'client-db') {
|
|
1534
|
+
port = source.port;
|
|
1535
|
+
}
|
|
1536
|
+
else {
|
|
1537
|
+
if (typeof SharedWorker === 'undefined') {
|
|
1538
|
+
throw new Error('SharedWorker is not available. ' +
|
|
1539
|
+
'Open this page over http:// (not file://) and use a supported browser.');
|
|
1540
|
+
}
|
|
1541
|
+
const worker = new SharedWorker(source, {
|
|
1542
|
+
type: 'classic',
|
|
1543
|
+
name: name ?? 'pyric-shared-worker',
|
|
1544
|
+
});
|
|
1545
|
+
port = worker.port;
|
|
1546
|
+
port.start();
|
|
1547
|
+
wirePort(port);
|
|
1548
|
+
}
|
|
1549
|
+
return { __kind: 'client-storage', port };
|
|
1550
|
+
}
|
|
1551
|
+
/** Build a Storage reference. Mirrors `pyric/storage`'s `ref(storage, path?)` /
|
|
1552
|
+
* `ref(parentRef, path)`. Client-side path math; no RPC. */
|
|
1553
|
+
export function ref(parent, path) {
|
|
1554
|
+
const rel = normalizeStorageRefPath(path ?? '');
|
|
1555
|
+
let fullPath;
|
|
1556
|
+
if (parent.__kind === 'client-storage') {
|
|
1557
|
+
fullPath = rel;
|
|
1558
|
+
}
|
|
1559
|
+
else {
|
|
1560
|
+
const base = parent.fullPath;
|
|
1561
|
+
fullPath = rel ? (base ? `${base}/${rel}` : rel) : base;
|
|
1562
|
+
}
|
|
1563
|
+
return { __kind: 'storage-ref', port: parent.port, fullPath, name: lastSegment(fullPath) };
|
|
1564
|
+
}
|
|
1565
|
+
/** Enumerate immediate child items + sub-prefixes under a ref (Pyric Studio
|
|
1566
|
+
* data browse). The host enforces `read` rules on the scanned prefix. */
|
|
1567
|
+
export async function listAll(reference) {
|
|
1568
|
+
const r = (await rpc(reference.port, {
|
|
1569
|
+
t: 'op', id: nextId(), method: 'storage.listAll', path: reference.fullPath,
|
|
1570
|
+
}));
|
|
1571
|
+
const mk = (e) => ({
|
|
1572
|
+
__kind: 'storage-ref', port: reference.port, fullPath: e.fullPath, name: e.name,
|
|
1573
|
+
});
|
|
1574
|
+
return { items: r.items.map(mk), prefixes: r.prefixes.map(mk) };
|
|
1575
|
+
}
|
|
1576
|
+
/** Read an object's metadata (Pyric Studio inspector). */
|
|
1577
|
+
export async function getMetadata(reference) {
|
|
1578
|
+
return (await rpc(reference.port, {
|
|
1579
|
+
t: 'op', id: nextId(), method: 'storage.getMetadata', path: reference.fullPath,
|
|
1580
|
+
}));
|
|
1581
|
+
}
|
|
1582
|
+
/** Read an object's bytes as a Blob (Pyric Studio inspector preview).
|
|
1583
|
+
* MessagePort-only — a Blob cannot cross the JSON bridge relay. */
|
|
1584
|
+
export async function getBlob(reference) {
|
|
1585
|
+
return (await rpc(reference.port, {
|
|
1586
|
+
t: 'op', id: nextId(), method: 'storage.getBlob', path: reference.fullPath,
|
|
1587
|
+
}));
|
|
1588
|
+
}
|
|
1589
|
+
/** Upload bytes at the reference's path (replaces existing content).
|
|
1590
|
+
* Mirrors `pyric/storage`'s `uploadBytes` result shape. */
|
|
1591
|
+
export async function uploadBytes(reference, data, metadata) {
|
|
1592
|
+
const bytes = data instanceof Blob
|
|
1593
|
+
? new Uint8Array(await data.arrayBuffer())
|
|
1594
|
+
: data instanceof ArrayBuffer
|
|
1595
|
+
? new Uint8Array(data)
|
|
1596
|
+
: data;
|
|
1597
|
+
if (bytes.byteLength > MAX_STORAGE_OP_BYTES) {
|
|
1598
|
+
throw storagePayloadTooLarge(bytes.byteLength, `uploadBytes payload for '${reference.fullPath}'`);
|
|
1599
|
+
}
|
|
1600
|
+
// contentType precedence mirrors pyric/storage: caller metadata → Blob.type.
|
|
1601
|
+
const contentType = metadata?.contentType ?? (data instanceof Blob && data.type ? data.type : undefined);
|
|
1602
|
+
const stored = (await rpc(reference.port, {
|
|
1603
|
+
t: 'op',
|
|
1604
|
+
id: nextId(),
|
|
1605
|
+
method: 'storage.putBytes',
|
|
1606
|
+
path: reference.fullPath,
|
|
1607
|
+
dataB64: bytesToBase64(bytes),
|
|
1608
|
+
...(contentType !== undefined ? { contentType } : {}),
|
|
1609
|
+
...(metadata !== undefined ? { metadata: metadata } : {}),
|
|
1610
|
+
}));
|
|
1611
|
+
return { ref: reference, metadata: stored };
|
|
1612
|
+
}
|
|
1613
|
+
/** Read an object's bytes (JSON-safe base64 op → `ArrayBuffer`). Mirrors
|
|
1614
|
+
* `pyric/storage`'s `getBytes`, including the optional client-side cap. */
|
|
1615
|
+
export async function getBytes(reference, maxDownloadSizeBytes) {
|
|
1616
|
+
const res = (await rpc(reference.port, {
|
|
1617
|
+
t: 'op', id: nextId(), method: 'storage.getBytes', path: reference.fullPath,
|
|
1618
|
+
}));
|
|
1619
|
+
if (typeof maxDownloadSizeBytes === 'number' && res.size > maxDownloadSizeBytes) {
|
|
1620
|
+
const err = new Error(`storage/quota-exceeded: object at '${reference.fullPath}' is ${res.size} bytes — ` +
|
|
1621
|
+
`over the requested maxDownloadSizeBytes (${maxDownloadSizeBytes}).`);
|
|
1622
|
+
err.code = 'storage/quota-exceeded';
|
|
1623
|
+
throw err;
|
|
1624
|
+
}
|
|
1625
|
+
const bytes = base64ToBytes(res.dataB64);
|
|
1626
|
+
return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
1627
|
+
}
|
|
1628
|
+
/** Delete the object at the reference's path (idempotent — missing = no-op,
|
|
1629
|
+
* matching the sandbox backend's delete semantics). */
|
|
1630
|
+
export async function deleteObject(reference) {
|
|
1631
|
+
await rpc(reference.port, {
|
|
1632
|
+
t: 'op', id: nextId(), method: 'storage.deleteObject', path: reference.fullPath,
|
|
1633
|
+
});
|
|
1634
|
+
}
|
|
1635
|
+
//# sourceMappingURL=client.js.map
|