@pyric/cli 0.1.0-alpha.17 → 0.1.0-alpha.18

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.
Files changed (171) hide show
  1. package/README.md +29 -3
  2. package/dist/bridge/server/bridge.d.ts.map +1 -1
  3. package/dist/bridge/server/bridge.js +4 -2
  4. package/dist/bridge/server/bridge.js.map +1 -1
  5. package/dist/bridge/server/peer.d.ts.map +1 -1
  6. package/dist/bridge/server/peer.js +1 -0
  7. package/dist/bridge/server/peer.js.map +1 -1
  8. package/dist/cli/serve.d.ts.map +1 -1
  9. package/dist/cli/serve.js +1 -0
  10. package/dist/cli/serve.js.map +1 -1
  11. package/dist/conformance/.generated/conformance-docs.d.ts.map +1 -1
  12. package/dist/conformance/.generated/conformance-docs.js +1 -1
  13. package/dist/conformance/.generated/conformance-docs.js.map +1 -1
  14. package/dist/functions-rtdb/child.d.ts +1 -0
  15. package/dist/functions-rtdb/child.d.ts.map +1 -1
  16. package/dist/functions-rtdb/child.js +11 -1
  17. package/dist/functions-rtdb/child.js.map +1 -1
  18. package/dist/functions-rtdb/development-runtime.d.ts +1 -0
  19. package/dist/functions-rtdb/development-runtime.d.ts.map +1 -1
  20. package/dist/functions-rtdb/development-runtime.js +1 -0
  21. package/dist/functions-rtdb/development-runtime.js.map +1 -1
  22. package/dist/remote/index.d.ts.map +1 -1
  23. package/dist/remote/index.js +5 -3
  24. package/dist/remote/index.js.map +1 -1
  25. package/dist/serve/runtime/chip.d.ts.map +1 -1
  26. package/dist/serve/runtime/chip.js +24 -3
  27. package/dist/serve/runtime/chip.js.map +1 -1
  28. package/dist/serve/runtime/status.d.ts +1 -0
  29. package/dist/serve/runtime/status.d.ts.map +1 -1
  30. package/dist/serve/runtime/status.js +71 -13
  31. package/dist/serve/runtime/status.js.map +1 -1
  32. package/dist/serve/site-ui/_astro/_slug_.C6QfVOxJ.css +1 -0
  33. package/dist/serve/site-ui/_astro/{app.bnmVTkIY.js → app.B7pBzz5N.js} +7 -7
  34. package/dist/serve/site-ui/_astro/app.boex5SnQ.js +1 -0
  35. package/dist/serve/site-ui/_astro/{chess-showcase.kC8dXLKY.js → chess-showcase.DDqE-QGe.js} +1 -1
  36. package/dist/serve/site-ui/_astro/{example-runtime.D79PnoSk.js → example-runtime.B0byNQOl.js} +1 -1
  37. package/dist/serve/site-ui/_astro/index.uwPvjH_1.js +1 -0
  38. package/dist/serve/site-ui/_astro/{reads.BYBRLbsE.js → reads.Dh3z0fJy.js} +1 -1
  39. package/dist/serve/site-ui/_astro/{sandbox-controls.C9Aaazt8.js → sandbox-controls.C2IqtoSw.js} +3 -3
  40. package/dist/serve/site-ui/_astro/{seed.DANAIyRw.js → seed.CCmj00su.js} +1 -1
  41. package/dist/serve/site-ui/auth/index.html +1 -1
  42. package/dist/serve/site-ui/docs/_rhythm/index.html +1 -1
  43. package/dist/serve/site-ui/docs/agent/set-up-your-agent/index.html +48 -13
  44. package/dist/serve/site-ui/docs/agent/set-up-your-agent.md +74 -11
  45. package/dist/serve/site-ui/docs/agent/watch-and-review/index.html +1 -1
  46. package/dist/serve/site-ui/docs/agent/work-with-an-agent/index.html +1 -1
  47. package/dist/serve/site-ui/docs/ai-compat/index.html +1 -1
  48. package/dist/serve/site-ui/docs/api-reference/index.html +1 -1
  49. package/dist/serve/site-ui/docs/app-compat/index.html +1 -1
  50. package/dist/serve/site-ui/docs/auth-compat/index.html +1 -1
  51. package/dist/serve/site-ui/docs/build/ai-logic/index.html +19 -2
  52. package/dist/serve/site-ui/docs/build/ai-logic.md +28 -0
  53. package/dist/serve/site-ui/docs/build/authentication/index.html +1 -1
  54. package/dist/serve/site-ui/docs/build/cloud-firestore/index.html +1 -1
  55. package/dist/serve/site-ui/docs/build/cloud-messaging/index.html +1 -1
  56. package/dist/serve/site-ui/docs/build/cloud-storage/index.html +1 -1
  57. package/dist/serve/site-ui/docs/build/realtime-database/index.html +1 -1
  58. package/dist/serve/site-ui/docs/conformance-scores/index.html +22 -7
  59. package/dist/serve/site-ui/docs/conformance-scores.md +20 -5
  60. package/dist/serve/site-ui/docs/create-pyric-reference-api/index.html +1 -1
  61. package/dist/serve/site-ui/docs/database-compat/index.html +1 -1
  62. package/dist/serve/site-ui/docs/examples/chess/index.html +2 -2
  63. package/dist/serve/site-ui/docs/examples/index.html +1 -1
  64. package/dist/serve/site-ui/docs/firestore-compat/index.html +1 -1
  65. package/dist/serve/site-ui/docs/functions-rtdb-compat/index.html +1 -1
  66. package/dist/serve/site-ui/docs/get-started/how-the-swap-works/index.html +1 -1
  67. package/dist/serve/site-ui/docs/get-started/nextjs/index.html +1 -1
  68. package/dist/serve/site-ui/docs/get-started/start-building/index.html +17 -5
  69. package/dist/serve/site-ui/docs/get-started/start-building.md +29 -3
  70. package/dist/serve/site-ui/docs/get-started/vite/index.html +1 -1
  71. package/dist/serve/site-ui/docs/index.json +43 -8
  72. package/dist/serve/site-ui/docs/messaging-compat/index.html +1 -1
  73. package/dist/serve/site-ui/docs/observe/resolve-runtime-status/index.html +1 -1
  74. package/dist/serve/site-ui/docs/observe/see-whats-happening/index.html +1 -1
  75. package/dist/serve/site-ui/docs/observe/shape-your-data/index.html +1 -1
  76. package/dist/serve/site-ui/docs/overview/index.html +1 -1
  77. package/dist/serve/site-ui/docs/pyric-admin-app-reference-api/index.html +1 -1
  78. package/dist/serve/site-ui/docs/pyric-admin-auth-reference-api/index.html +1 -1
  79. package/dist/serve/site-ui/docs/pyric-admin-database-reference-api/index.html +1 -1
  80. package/dist/serve/site-ui/docs/pyric-admin-firestore-reference-api/index.html +1 -1
  81. package/dist/serve/site-ui/docs/pyric-admin-messaging-reference-api/index.html +1 -1
  82. package/dist/serve/site-ui/docs/pyric-admin-storage-reference-api/index.html +1 -1
  83. package/dist/serve/site-ui/docs/pyric-ai-reference-api/index.html +1 -1
  84. package/dist/serve/site-ui/docs/pyric-ai-scripting-reference-api/index.html +1 -1
  85. package/dist/serve/site-ui/docs/pyric-app-reference-api/index.html +1 -1
  86. package/dist/serve/site-ui/docs/pyric-auth-reference-api/index.html +1 -1
  87. package/dist/serve/site-ui/docs/pyric-cli-assurance-browser-reference-api/index.html +1 -1
  88. package/dist/serve/site-ui/docs/pyric-cli-assurance-reference-api/index.html +1 -1
  89. package/dist/serve/site-ui/docs/pyric-cli-bridge-client-reference-api/index.html +1 -1
  90. package/dist/serve/site-ui/docs/pyric-cli-bridge-reference-api/index.html +1 -1
  91. package/dist/serve/site-ui/docs/pyric-cli-conformance-browser-reference-api/index.html +1 -1
  92. package/dist/serve/site-ui/docs/pyric-cli-conformance-docs-reference-api/index.html +1 -1
  93. package/dist/serve/site-ui/docs/pyric-cli-conformance-reference-api/index.html +1 -1
  94. package/dist/serve/site-ui/docs/pyric-cli-credentials-node-reference-api/index.html +1 -1
  95. package/dist/serve/site-ui/docs/pyric-cli-discover-reference-api/index.html +1 -1
  96. package/dist/serve/site-ui/docs/pyric-cli-next-reference-api/index.html +1 -1
  97. package/dist/serve/site-ui/docs/pyric-cli-register-app-bridge-reference-api/index.html +1 -1
  98. package/dist/serve/site-ui/docs/pyric-cli-register-reference-api/index.html +1 -1
  99. package/dist/serve/site-ui/docs/pyric-cli-remote-reference-api/index.html +1 -1
  100. package/dist/serve/site-ui/docs/pyric-cli-serve-worker-reference-api/index.html +1 -1
  101. package/dist/serve/site-ui/docs/pyric-cli-verify-reference-api/index.html +1 -1
  102. package/dist/serve/site-ui/docs/pyric-cli-vite-reference-api/index.html +1 -1
  103. package/dist/serve/site-ui/docs/pyric-database-reference-api/index.html +1 -1
  104. package/dist/serve/site-ui/docs/pyric-firestore-reference-api/index.html +1 -1
  105. package/dist/serve/site-ui/docs/pyric-messaging-reference-api/index.html +1 -1
  106. package/dist/serve/site-ui/docs/pyric-messaging-sw-reference-api/index.html +1 -1
  107. package/dist/serve/site-ui/docs/pyric-rules-reference-api/index.html +1 -1
  108. package/dist/serve/site-ui/docs/pyric-sandbox-database-reference-api/index.html +1 -1
  109. package/dist/serve/site-ui/docs/pyric-sandbox-firestore-reference-api/index.html +1 -1
  110. package/dist/serve/site-ui/docs/pyric-sandbox-reference-api/index.html +1 -1
  111. package/dist/serve/site-ui/docs/pyric-storage-reference-api/index.html +1 -1
  112. package/dist/serve/site-ui/docs/pyric-ui-agents-reference-api/index.html +1 -1
  113. package/dist/serve/site-ui/docs/pyric-ui-auth-hooks-reference-api/index.html +1 -1
  114. package/dist/serve/site-ui/docs/pyric-ui-auth-reference-api/index.html +1 -1
  115. package/dist/serve/site-ui/docs/pyric-ui-events-hooks-reference-api/index.html +1 -1
  116. package/dist/serve/site-ui/docs/pyric-ui-events-reference-api/index.html +1 -1
  117. package/dist/serve/site-ui/docs/pyric-ui-firestore-hooks-reference-api/index.html +1 -1
  118. package/dist/serve/site-ui/docs/pyric-ui-firestore-reference-api/index.html +1 -1
  119. package/dist/serve/site-ui/docs/pyric-ui-primitives-reference-api/index.html +1 -1
  120. package/dist/serve/site-ui/docs/pyric-ui-rtdb-reference-api/index.html +1 -1
  121. package/dist/serve/site-ui/docs/pyric-ui-rules-hooks-reference-api/index.html +1 -1
  122. package/dist/serve/site-ui/docs/pyric-ui-rules-reference-api/index.html +1 -10
  123. package/dist/serve/site-ui/docs/pyric-ui-rules-reference-api.md +0 -9
  124. package/dist/serve/site-ui/docs/pyric-ui-storage-hooks-reference-api/index.html +1 -1
  125. package/dist/serve/site-ui/docs/pyric-ui-storage-reference-api/index.html +1 -1
  126. package/dist/serve/site-ui/docs/pyric-ui-traffic-hooks-reference-api/index.html +1 -1
  127. package/dist/serve/site-ui/docs/pyric-ui-traffic-reference-api/index.html +1 -1
  128. package/dist/serve/site-ui/docs/rules-compat/index.html +1 -1
  129. package/dist/serve/site-ui/docs/secure/audit-your-rules/index.html +1 -1
  130. package/dist/serve/site-ui/docs/secure/firestore-rules-limits/index.html +1 -1
  131. package/dist/serve/site-ui/docs/secure/read-a-denial/index.html +1 -1
  132. package/dist/serve/site-ui/docs/secure/rtdb-rules-in-typescript/index.html +1 -1
  133. package/dist/serve/site-ui/docs/secure/rules-standard-library/index.html +1 -1
  134. package/dist/serve/site-ui/docs/secure/secure-it-with-rules/index.html +1 -1
  135. package/dist/serve/site-ui/docs/secure/simulate-and-lint/index.html +1 -1
  136. package/dist/serve/site-ui/docs/secure/write-a-rules-test-suite/index.html +1 -1
  137. package/dist/serve/site-ui/docs/ship/ship-to-production/index.html +1 -1
  138. package/dist/serve/site-ui/docs/ship/test-in-node/index.html +1 -1
  139. package/dist/serve/site-ui/docs/storage-compat/index.html +1 -1
  140. package/dist/serve/site-ui/docs/trust/how-we-know-it-matches-firebase/index.html +1 -1
  141. package/dist/serve/site-ui/docs/trust/rules-standard-library/index.html +1 -1
  142. package/dist/serve/site-ui/docs/trust/storage-rules-stdlib-research/index.html +1 -1
  143. package/dist/serve/site-ui/docs/trust/versioning-and-compatibility/index.html +1 -1
  144. package/dist/serve/site-ui/docs/tutorial/index.html +2 -1
  145. package/dist/serve/site-ui/docs/tutorial.md +2 -0
  146. package/dist/serve/site-ui/examples/chess/index.html +1 -1
  147. package/dist/serve/site-ui/examples/firestore-first-write/index.html +1 -1
  148. package/dist/serve/site-ui/firestore/index.html +1 -1
  149. package/dist/serve/site-ui/index.html +1 -1
  150. package/dist/serve/site-ui/llms.txt +2 -2
  151. package/dist/serve/site-ui/rtdb/index.html +1 -1
  152. package/dist/serve/site-ui/settings/index.html +1 -1
  153. package/dist/serve/site-ui/storage/index.html +1 -1
  154. package/dist/serve/site-ui/traffic/index.html +1 -1
  155. package/dist/serve/vite-functions-development.d.ts.map +1 -1
  156. package/dist/serve/vite-functions-development.js +1 -0
  157. package/dist/serve/vite-functions-development.js.map +1 -1
  158. package/package.json +4 -4
  159. package/src/bridge/server/bridge.ts +5 -2
  160. package/src/bridge/server/peer.ts +2 -1
  161. package/src/cli/serve.ts +1 -0
  162. package/src/conformance/.generated/conformance-docs.ts +1 -1
  163. package/src/functions-rtdb/child.ts +12 -1
  164. package/src/functions-rtdb/development-runtime.ts +2 -0
  165. package/src/remote/index.ts +7 -5
  166. package/src/serve/runtime/chip.ts +24 -3
  167. package/src/serve/runtime/status.ts +76 -13
  168. package/src/serve/vite-functions-development.ts +1 -0
  169. package/dist/serve/site-ui/_astro/_slug_.BoKXYrnu.css +0 -1
  170. package/dist/serve/site-ui/_astro/app.t6u-adB_.js +0 -1
  171. package/dist/serve/site-ui/_astro/index.DzVde04M.js +0 -1
@@ -61,6 +61,7 @@ export interface SpawnFunctionsRtdbChildOptions {
61
61
  instance: string;
62
62
  location: string;
63
63
  databaseHost?: string;
64
+ projectId?: string;
64
65
  childModuleUrl?: string | URL;
65
66
  nodeExecutable?: string;
66
67
  onEvent?(event: FunctionsRtdbChildEvent): void;
@@ -104,6 +105,14 @@ export function spawnFunctionsRtdbChild(
104
105
  const childModulePath = typeof childModuleUrl === 'string' && !childModuleUrl.startsWith('file:')
105
106
  ? resolve(childModuleUrl)
106
107
  : fileURLToPath(childModuleUrl);
108
+ const projectId = options.projectId ?? options.instance.replace(/-default-rtdb$/, '') ?? 'demo-project';
109
+ const databaseHost = options.databaseHost ?? 'firebasedatabase.app';
110
+ const databaseURL = `https://${options.instance}.${databaseHost}`;
111
+ const firebaseConfig = JSON.stringify({
112
+ projectId,
113
+ databaseURL,
114
+ storageBucket: `${projectId}.appspot.com`,
115
+ });
107
116
  const child = spawn(options.nodeExecutable ?? 'node', [childModulePath], {
108
117
  cwd: options.cwd,
109
118
  env: {
@@ -112,7 +121,9 @@ export function spawnFunctionsRtdbChild(
112
121
  PYRIC_FUNCTIONS_ENTRY: resolve(options.entry),
113
122
  PYRIC_FUNCTIONS_INSTANCE: options.instance,
114
123
  PYRIC_FUNCTIONS_LOCATION: options.location,
115
- PYRIC_FUNCTIONS_DATABASE_HOST: options.databaseHost ?? 'firebasedatabase.app',
124
+ PYRIC_FUNCTIONS_DATABASE_HOST: databaseHost,
125
+ GCLOUD_PROJECT: options.env.GCLOUD_PROJECT ?? projectId,
126
+ FIREBASE_CONFIG: options.env.FIREBASE_CONFIG ?? firebaseConfig,
116
127
  },
117
128
  stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
118
129
  });
@@ -40,6 +40,7 @@ export interface FunctionsDevelopmentRuntimeOptions {
40
40
  registerUrl: string;
41
41
  instance: string;
42
42
  location: string;
43
+ projectId?: string;
43
44
  childModuleUrl?: string | URL;
44
45
  readiness: FunctionsPeerReadiness;
45
46
  onEvent?(event: FunctionsDevelopmentEvent): void;
@@ -218,6 +219,7 @@ export function createFunctionsDevelopmentRuntime(
218
219
  }),
219
220
  instance: options.instance,
220
221
  location: options.location,
222
+ ...(options.projectId === undefined ? {} : { projectId: options.projectId }),
221
223
  ...(options.childModuleUrl === undefined ? {} : { childModuleUrl: options.childModuleUrl }),
222
224
  onEvent: (event) => emit({ type: 'child-event', event }),
223
225
  });
@@ -60,13 +60,15 @@ function remoteError(
60
60
  code: string,
61
61
  message: string,
62
62
  denialContext?: unknown,
63
- ): Error & { code: string; denialContext?: unknown } {
64
- const err = new Error(message) as Error & { code: string; denialContext?: unknown };
63
+ envelope?: unknown,
64
+ ): Error & { code: string; denialContext?: unknown; envelope?: unknown } {
65
+ const err = new Error(message) as Error & { code: string; denialContext?: unknown; envelope?: unknown };
65
66
  err.code = code;
66
67
  // Structured denial context (spike gap 6): a relayed permission-denied
67
68
  // carries the same "why did this deny" frame a local SandboxError has —
68
69
  // plain JSON off the wire, re-attached here.
69
70
  if (denialContext !== undefined) err.denialContext = denialContext;
71
+ if (envelope !== undefined) err.envelope = envelope;
70
72
  return err;
71
73
  }
72
74
 
@@ -406,7 +408,7 @@ export function createRemoteSandboxCore(
406
408
  ' — the running sandbox may predate this feature; restart pyric dev ' +
407
409
  'and close other open pages of this origin, then reload.';
408
410
  }
409
- call.reject(remoteError(code, message, msg.error?.denialContext));
411
+ call.reject(remoteError(code, message, msg.error?.denialContext, (msg.error as any)?.envelope));
410
412
  }
411
413
  return;
412
414
  }
@@ -430,8 +432,8 @@ export function createRemoteSandboxCore(
430
432
  send({ type: 'worker-unsub', subId: msg.subId });
431
433
  } catch {}
432
434
  }
433
- const payload = value.__error as { code: string; message: string; denialContext?: unknown };
434
- const err = remoteError(payload.code, payload.message, payload.denialContext);
435
+ const payload = value.__error as { code: string; message: string; denialContext?: unknown; envelope?: unknown };
436
+ const err = remoteError(payload.code, payload.message, payload.denialContext, payload.envelope);
435
437
  if (sub.onError) sub.onError(err);
436
438
  else console.error('pyric remote sandbox: uncaught error in subscription:', err);
437
439
  return;
@@ -94,9 +94,12 @@ const styles = `
94
94
  .errors { background: var(--pyric-content); border-bottom: 1px solid var(--pyric-border-soft); border-top: 1px solid var(--pyric-border-soft); max-height: 184px; min-height: 58px; overflow-y: auto; }
95
95
  .errors::-webkit-scrollbar { width: 8px; }
96
96
  .errors::-webkit-scrollbar-thumb { background: #33333f; border-radius: 4px; }
97
- .error-row { align-items: flex-start; border-bottom: 1px solid rgba(42,42,53,.7); display: grid; gap: 8px; grid-template-columns: 18px minmax(0,1fr) 28px; padding: 10px 8px 10px 12px; }
97
+ .error-row { align-items: flex-start; border-bottom: 1px solid rgba(42,42,53,.7); display: grid; gap: 8px; grid-template-columns: 18px minmax(0,1fr) 28px 28px; padding: 10px 8px 10px 12px; }
98
98
  .error-row:last-child { border-bottom: 0; }
99
99
  .error-number { color: var(--pyric-error); font: 10px/20px ui-monospace, monospace; }
100
+ .panel-controls { align-items: center; display: inline-flex; gap: 4px; }
101
+ .clear-button { background: transparent; border: 0; color: var(--pyric-muted); cursor: pointer; font-size: 11px; margin-left: 8px; padding: 2px 6px; }
102
+ .clear-button:hover { color: var(--pyric-text); }
100
103
  .error-body { min-width: 0; }
101
104
  .error-body code { color: #d7d7df; display: block; font-size: 11px; line-height: 1.55; overflow-wrap: anywhere; white-space: pre-wrap; }
102
105
  .error-meta { color: var(--pyric-muted); font: 9px/1.4 ui-monospace, monospace; margin-top: 4px; overflow-wrap: anywhere; }
@@ -122,6 +125,7 @@ const styles = `
122
125
 
123
126
  const icons = {
124
127
  close: '<svg class="icon" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="m6 6 12 12M18 6 6 18"/></svg>',
128
+ minimize: '<svg class="icon" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M5 12h14"/></svg>',
125
129
  copy: '<svg class="icon" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="8" y="8" width="11" height="11" rx="1"/><path d="M16 8V5H5v11h3"/></svg>',
126
130
  chevron: '<svg class="chevron" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="m6 15 6-6 6 6"/></svg>',
127
131
  external: '<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M14 5h5v5M19 5l-8 8"/><path d="M19 13v6H5V5h6"/></svg>',
@@ -148,6 +152,7 @@ function renderErrors(snapshot: PyricRuntimeSnapshot, canCopy: boolean): string
148
152
  <span class="error-number">${String(index + 1).padStart(2, '0')}</span>
149
153
  <div class="error-body"><code></code><div class="error-meta"></div></div>
150
154
  <button class="icon-button" type="button" data-copy-error="${escapeAttribute(error.id)}" aria-label="${canCopy ? `Copy error ${index + 1}` : 'Copy unavailable'}" title="${canCopy ? 'Copy error' : 'Clipboard unavailable'}" ${canCopy ? '' : 'disabled'}>${icons.copy}</button>
155
+ <button class="icon-button" type="button" data-dismiss-error="${escapeAttribute(error.id)}" aria-label="Dismiss error ${index + 1}" title="Dismiss error">${icons.close}</button>
151
156
  </div>
152
157
  `).join('');
153
158
  }
@@ -202,8 +207,11 @@ export function mountPyricRuntimeChip(options: PyricRuntimeChipOptions): PyricRu
202
207
  view.innerHTML = `${open ? `
203
208
  <section class="panel" role="dialog" aria-label="Pyric runtime">
204
209
  <header class="panel-header">
205
- <div class="panel-title"><span class="brand-mark">&gt;_</span><strong>Pyric runtime</strong>${errorCount > 0 ? `<span class="count">${errorCount} ${errorCount === 1 ? 'error' : 'errors'}</span>` : ''}</div>
206
- <button class="icon-button" type="button" data-collapse aria-label="Collapse Pyric runtime">${icons.close}</button>
210
+ <div class="panel-title"><span class="brand-mark">&gt;_</span><strong>Pyric runtime</strong>${errorCount > 0 ? `<span class="count">${errorCount} ${errorCount === 1 ? 'error' : 'errors'}</span><button class="clear-button" type="button" data-clear-errors aria-label="Clear all errors">Clear</button>` : ''}</div>
211
+ <div class="panel-controls">
212
+ <button class="icon-button" type="button" data-collapse aria-label="Minimize Pyric runtime">${icons.minimize}</button>
213
+ <button class="icon-button" type="button" data-dismiss-chip aria-label="Dismiss Pyric runtime from page">${icons.close}</button>
214
+ </div>
207
215
  </header>
208
216
  <div class="worker-state"><span class="state-label${snapshot.updateAvailable ? ' available' : ''}"><span class="mini-dot"></span>${workerLabel}</span><span class="epochs">${epochs}</span></div>
209
217
  <div class="errors" data-error-viewport>${renderErrors(snapshot, Boolean(clipboard))}</div>
@@ -247,6 +255,12 @@ export function mountPyricRuntimeChip(options: PyricRuntimeChipOptions): PyricRu
247
255
  render();
248
256
  root.querySelector<HTMLButtonElement>('[data-expand]')?.focus();
249
257
  });
258
+ root.querySelector('[data-clear-errors]')?.addEventListener('click', () => {
259
+ options.runtime.clearErrors();
260
+ });
261
+ root.querySelector('[data-dismiss-chip]')?.addEventListener('click', () => {
262
+ host.style.display = 'none';
263
+ });
250
264
  root.querySelector('[data-update-worker]')?.addEventListener('click', () => {
251
265
  if (!snapshot.updateAvailable || snapshot.updatingWorker) return;
252
266
  void options.runtime.updateWorker().catch(() => { /* status records and renders the failure */ });
@@ -262,6 +276,13 @@ export function mountPyricRuntimeChip(options: PyricRuntimeChipOptions): PyricRu
262
276
  });
263
277
  });
264
278
  }
279
+ for (const button of root.querySelectorAll<HTMLButtonElement>('[data-dismiss-error]')) {
280
+ button.addEventListener('click', () => {
281
+ if (button.dataset.dismissError) {
282
+ options.runtime.dismissError(button.dataset.dismissError);
283
+ }
284
+ });
285
+ }
265
286
  if (focusToken) {
266
287
  const candidates = root.querySelectorAll<HTMLElement>(`[${focusToken.attribute}]`);
267
288
  const replacement = [...candidates].find((candidate) =>
@@ -36,6 +36,7 @@ export interface PyricRuntimeStatus {
36
36
  reportError(error: unknown, source: PyricRuntimeErrorSource): void;
37
37
  recordSandboxEvents(events: readonly SandboxEvent[]): void;
38
38
  clearErrors(): void;
39
+ dismissError(id: string): void;
39
40
  }
40
41
 
41
42
  let nextErrorId = 0;
@@ -77,41 +78,95 @@ export function normalizePyricRuntimeError(
77
78
  return { id, source, at, message: String(value) };
78
79
  }
79
80
 
81
+ function isOperationOrRequestEvent(event: SandboxEvent): boolean {
82
+ const isOperationKind = event.kind === 'operation';
83
+ const isRequestKind = event.kind === 'request';
84
+ return isOperationKind || isRequestKind;
85
+ }
86
+
87
+ function isDeniedOperationEvent(event: SandboxEvent): boolean {
88
+ const isTargetEventKind = isOperationOrRequestEvent(event);
89
+ const hasResultProperty = 'result' in event;
90
+ const isDeniedResult = hasResultProperty && event.result === 'deny';
91
+ return isTargetEventKind && isDeniedResult;
92
+ }
93
+
94
+ function isRuntimeErrorEvent(event: SandboxEvent): boolean {
95
+ return event.kind === 'runtime_error';
96
+ }
97
+
98
+ function isListenerErroredEvent(event: SandboxEvent): boolean {
99
+ const isListenerErroredKind = event.kind === 'listener_errored';
100
+ const hasErrorPayload = 'error' in event && Boolean(event.error);
101
+ return isListenerErroredKind && hasErrorPayload;
102
+ }
103
+
104
+ function isListenerPhaseErroredEvent(event: SandboxEvent): boolean {
105
+ const isListenerKind = event.kind === 'listener';
106
+ const isErroredPhase = 'phase' in event && event.phase === 'errored';
107
+ const hasErrorPayload = 'error' in event && Boolean(event.error);
108
+ return isListenerKind && isErroredPhase && hasErrorPayload;
109
+ }
110
+
80
111
  function sandboxError(event: SandboxEvent): PyricRuntimeError | null {
81
- if (event.kind === 'runtime_error') {
112
+ if (isRuntimeErrorEvent(event)) {
113
+ const hasPathProperty = 'path' in event && typeof event.path === 'string';
114
+ const targetPath = hasPathProperty ? event.path : undefined;
115
+ const hasMethodProperty = 'method' in event && typeof event.method === 'string';
116
+ const targetMethod = hasMethodProperty ? event.method : 'unknown';
117
+ const hasErrorPayload = 'error' in event && Boolean(event.error);
118
+ const errorPayload = hasErrorPayload ? (event as { error: { code?: string; message: string } }).error : undefined;
82
119
  return {
83
120
  id: event.id,
84
121
  source: 'sandbox',
85
122
  at: event.at,
86
123
  service: event.service,
87
- method: event.method,
88
- ...(event.path ? { path: event.path } : {}),
89
- ...(event.error.code ? { code: event.error.code } : {}),
90
- message: event.error.message,
124
+ method: targetMethod,
125
+ ...(targetPath ? { path: targetPath } : {}),
126
+ ...(errorPayload?.code ? { code: errorPayload.code } : {}),
127
+ message: errorPayload?.message ? errorPayload.message : 'Sandbox runtime error',
91
128
  };
92
129
  }
93
- if (event.kind === 'listener_errored' && event.error) {
130
+ if (isListenerErroredEvent(event)) {
131
+ const errorPayload = (event as { error: { code?: string; message: string } }).error;
94
132
  return {
95
133
  id: event.id,
96
134
  source: 'sandbox',
97
135
  at: event.at,
98
136
  service: 'firestore',
99
137
  method: 'listener',
100
- ...('path' in event.target ? { path: event.target.path } : {}),
101
- code: event.error.code,
102
- message: event.error.message,
138
+ ...('target' in event && event.target && 'path' in event.target ? { path: event.target.path } : {}),
139
+ code: errorPayload.code,
140
+ message: errorPayload.message,
103
141
  };
104
142
  }
105
- if (event.kind === 'listener' && event.phase === 'errored' && event.error) {
143
+ if (isListenerPhaseErroredEvent(event)) {
144
+ const errorPayload = (event as { error: { code?: string; message: string } }).error;
106
145
  return {
107
146
  id: event.id,
108
147
  source: 'sandbox',
109
148
  at: event.at,
110
149
  service: event.service,
111
150
  method: 'listener',
112
- ...(event.target.path ? { path: event.target.path } : {}),
113
- ...(event.error.code ? { code: event.error.code } : {}),
114
- message: event.error.message,
151
+ ...('target' in event && event.target && 'path' in event.target ? { path: event.target.path } : {}),
152
+ ...(errorPayload.code ? { code: errorPayload.code } : {}),
153
+ message: errorPayload.message,
154
+ };
155
+ }
156
+ if (isDeniedOperationEvent(event)) {
157
+ const hasPathProperty = 'path' in event && typeof event.path === 'string';
158
+ const targetPath = hasPathProperty ? event.path : '(service)';
159
+ const hasMethodProperty = 'method' in event && typeof event.method === 'string';
160
+ const targetMethod = hasMethodProperty ? event.method : 'operation';
161
+ return {
162
+ id: event.id,
163
+ source: 'sandbox',
164
+ at: event.at,
165
+ service: event.service,
166
+ method: targetMethod,
167
+ path: targetPath,
168
+ code: 'PERMISSION_DENIED',
169
+ message: `PERMISSION_DENIED: ${targetMethod} on ${targetPath} denied by rules`,
115
170
  };
116
171
  }
117
172
  return null;
@@ -201,6 +256,14 @@ export function createPyricRuntimeStatus(
201
256
  errorIds.clear();
202
257
  publish({ ...snapshot, errors: [] });
203
258
  },
259
+ dismissError(id) {
260
+ if (!errorIds.has(id)) return;
261
+ errorIds.delete(id);
262
+ publish({
263
+ ...snapshot,
264
+ errors: snapshot.errors.filter((err) => err.id !== id),
265
+ });
266
+ },
204
267
  };
205
268
  }
206
269
 
@@ -144,6 +144,7 @@ export function attachViteFunctionsDevelopment(
144
144
  registerUrl: options.registerUrl,
145
145
  instance: options.instance ?? `${options.projectId}-default-rtdb`,
146
146
  location: options.region ?? options.baseEnv.PYRIC_FUNCTIONS_RTDB_REGION ?? 'us-central1',
147
+ projectId: options.projectId,
147
148
  readiness: createInProcessFunctionsPeerReadiness(bridge.sandboxConnected),
148
149
  onEvent: (event) => reportEvent(options.logger, event),
149
150
  ...(options.childModuleUrl === undefined ? {} : { childModuleUrl: options.childModuleUrl }),
@@ -1 +0,0 @@
1
- .prose .conformance-flow{display:flex;flex-wrap:wrap;align-items:stretch;gap:var(--space-2)}.prose .flow-step{flex:1 1 0;min-width:92px;display:flex;flex-direction:column;justify-content:center;gap:var(--space-1);padding:var(--space-3);text-align:center;background:var(--panel);border:1px solid var(--line);border-radius:8px;font-size:.9rem;font-weight:550;line-height:1.3;color:var(--ink)}.prose .flow-sub{font-size:var(--fs-caption);font-weight:400;color:var(--muted)}.prose .flow-arrow{display:flex;align-items:center;color:var(--faint);font-size:1.1rem}.prose .compat-stat{display:flex;flex-direction:column;gap:var(--space-3);padding-top:var(--space-4);border-top:1px solid var(--line)}.prose .compat-stat-surface{font-size:.85rem;color:var(--muted);font-variant-numeric:tabular-nums}.prose .compat-stat-surface strong,.prose .compat-stat-item strong{color:var(--ink)}.prose .compat-stat-figure{display:flex;align-items:baseline;flex-wrap:wrap;gap:var(--space-3);line-height:1}.prose .compat-stat-pct{font-size:2.75rem;font-weight:750;line-height:1;letter-spacing:-.02em;color:var(--ink);font-variant-numeric:tabular-nums}.prose .compat-stat-label{font-size:1rem;color:var(--muted)}.prose .compat-stat-denom{font-size:.85rem;color:var(--faint);font-variant-numeric:tabular-nums}.prose .compat-stat-bar{display:flex;gap:2px;width:100%;height:10px;border-radius:5px;overflow:hidden}.prose .compat-stat-seg{flex-basis:0;min-width:0;background:var(--muted)}.prose .compat-stat-seg[data-status=ok]{background:var(--diff-add)}.prose .compat-stat-seg[data-status=unsupported]{background:var(--line-2)}.prose .compat-stat-seg[data-status=unverified]{background:transparent;box-shadow:inset 0 0 0 1px var(--faint)}.prose .compat-stat-seg[data-status=diverged]{background:repeating-linear-gradient(135deg,var(--accent) 0 4px,color-mix(in srgb,var(--accent) 45%,transparent) 4px 7px)}.prose .compat-stat-seg[data-status=bug]{background:repeating-linear-gradient(45deg,var(--diff-remove) 0 3px,color-mix(in srgb,var(--diff-remove) 40%,transparent) 3px 6px)}.prose .compat-stat-key{padding:0;display:flex;flex-wrap:wrap;gap:var(--space-2) var(--space-4);list-style:none}.prose .compat-stat-item{display:inline-flex;align-items:center;gap:var(--space-2);font-size:var(--fs-caption);color:var(--muted);font-variant-numeric:tabular-nums}.prose .compat-stat-note{font-size:var(--fs-caption);color:var(--muted)}.prose .compat-meters{display:flex;flex-direction:column;gap:var(--space-2)}.prose .compat-meter{display:grid;grid-template-columns:minmax(9rem,auto) 1fr auto;align-items:center;gap:var(--space-3);font-size:var(--fs-caption);color:var(--muted);font-variant-numeric:tabular-nums}.prose .compat-meter-label{color:var(--muted)}.prose .compat-meter-value{color:var(--ink);font-weight:600;text-align:right}.prose .compat-meter-track{display:block;width:100%;height:8px;border-radius:4px;background:var(--line-2);overflow:hidden}.prose .compat-meter-fill{display:block;height:100%;border-radius:4px;background:var(--diff-add)}.prose .compat-meter-track--mini{height:5px;margin-top:var(--space-1)}.prose .compat-score-table{width:100%;border-collapse:collapse;font-size:.875rem}.prose .compat-score-table thead th{text-align:left;font-size:.6875rem;font-weight:600;text-transform:uppercase;letter-spacing:.06em;color:var(--ink-3, #667);padding:var(--space-2) var(--space-3);border-bottom:1px solid var(--line)}.prose .compat-score-table td,.prose .compat-score-table th[scope=row]{padding:var(--space-2) var(--space-3);border-bottom:1px solid var(--line);vertical-align:middle;text-align:left}.prose .compat-score-table th[scope=row]{font-weight:600;white-space:nowrap}.prose .compat-score-cell{white-space:nowrap}.prose .compat-score-cell .compat-score-pct{font-variant-numeric:tabular-nums;font-weight:600;margin-right:var(--space-2)}.prose .compat-score-cell .compat-meter-track--mini{display:inline-block;width:8rem;vertical-align:middle}.prose .compat-score-detail{color:var(--ink-3, #667);font-size:.8125rem;white-space:nowrap}.prose .compat-score-row--overall th[scope=row],.prose .compat-score-row--overall td{border-top:2px solid var(--line);border-bottom:0}.prose .compat-score-tbd{color:var(--ink-3, #667);font-size:.8125rem;font-style:italic}.prose .compat-score-stack{display:grid;gap:var(--space-1)}.prose .compat-score-bar{display:flex;align-items:center;gap:var(--space-2)}.prose .compat-score-bar .compat-meter-track{flex:1 1 auto}.prose .compat-score-basis{font-size:.8125rem;color:var(--ink-3, #667)}:root{--rhythm-para: .875rem;--rhythm-group: 1.5rem;--rhythm-subsection: 2.25rem;--rhythm-section: 3.25rem;--rhythm-list: calc(var(--rhythm-para) * .75)}.prose>*,.prose blockquote>*,.prose li>*,.prose .compat-stat>*{margin-block:0}.prose>*+*{margin-block-start:var(--rhythm-group)}.prose>*+h2{margin-block-start:var(--rhythm-section)}.prose>*+h3,.prose>*+h4{margin-block-start:var(--rhythm-subsection)}.prose>h1+*,.prose>h2+*,.prose>h3+*,.prose>h4+*{margin-block-start:var(--rhythm-para)}.prose>p+p{margin-block-start:var(--rhythm-para)}.prose>p+ul,.prose>p+ol,.prose>p+blockquote{margin-block-start:var(--rhythm-para)}.prose li+li{margin-block-start:var(--rhythm-list)}.prose li>ul,.prose li>ol{margin-block-start:var(--rhythm-list)}.prose li>*+*,.prose blockquote>*+*{margin-block-start:var(--rhythm-para)}.api-reference-header{margin:0 0 2.5rem;padding:0 0 2rem;border-bottom:1px solid var(--line)}.api-reference-kicker{margin:0 0 .65rem;color:var(--muted);font-size:var(--fs-micro);font-weight:600;letter-spacing:var(--tracking-micro);text-transform:uppercase}.api-reference-header h1{margin:0;color:var(--ink);font-size:clamp(1.7rem,4vw,2.45rem);font-weight:600;letter-spacing:-.035em}.api-reference-header h1 code{padding:0;color:inherit;background:transparent;font:inherit}.api-reference-meta,.api-reference-source{margin:.7rem 0 0;color:var(--muted);font-size:var(--fs-body)}.api-reference-source{margin-top:.3rem}.api-reference-evidence{display:inline-block;margin-top:1rem;color:var(--ink);font-size:var(--fs-label);font-weight:600;text-underline-offset:.18em}.api-reference-body>h2{margin-top:3.75rem;padding-bottom:.65rem;border-bottom:1px solid var(--line)}.api-reference-body>h3{margin-top:2.75rem}.api-reference-body>h3 code{font-size:inherit}.api-reference-body h4{margin-top:1.8rem}.api-reference-body h5,.api-reference-body h6{margin-top:1.35rem}.api-reference-body pre{overflow-x:auto}.api-reference-body table{display:block;max-width:100%;overflow-x:auto;white-space:nowrap}.api-symbols{max-height:calc(100vh - 5rem);overflow:auto;scrollbar-width:thin}.api-symbol-filter{width:100%;margin:.2rem 0 1rem;padding:.5rem .6rem;border:1px solid var(--line);border-radius:.35rem;color:var(--ink);background:var(--panel);font:inherit;font-size:var(--fs-caption)}.api-symbol-filter:focus{border-color:var(--muted);outline:none}.api-symbol-group+.api-symbol-group{margin-top:1rem}.api-symbol-kind{display:block;margin-bottom:.35rem;color:var(--muted);font-size:var(--fs-micro);font-weight:600;letter-spacing:var(--tracking-micro);text-transform:uppercase}.api-symbol-group ul{margin:0;padding:0;list-style:none}.api-symbol-group li+li{margin-top:.22rem}.api-symbol-group li a{display:block;overflow:hidden;color:var(--muted);font-family:var(--font-mono);font-size:var(--fs-caption);text-overflow:ellipsis;white-space:nowrap}.api-symbol-group li a:hover,.api-symbol-kind:hover{color:var(--ink)}.api-symbol-empty{color:var(--muted);font-size:var(--fs-caption)}.docs-shell--example[data-astro-cid-mw7aashj]{max-width:100rem;grid-template-columns:minmax(200px,240px) minmax(0,1fr)}.docs-shell--example[data-astro-cid-mw7aashj] .doc-toc[data-astro-cid-mw7aashj]{display:none}.doc-main--example[data-astro-cid-mw7aashj]{max-width:70rem}@media(max-width:800px){.docs-shell--example[data-astro-cid-mw7aashj]{grid-template-columns:minmax(0,1fr)}}.example-stage[data-astro-cid-xgvwrve7]{width:100%;margin:0;border:1px solid var(--line);border-radius:.5rem;overflow:hidden;background:#15151d}iframe[data-astro-cid-xgvwrve7]{display:block;width:100%;height:19rem;border:0;overflow:hidden;background:#15151d}.is-showcase[data-astro-cid-xgvwrve7] iframe[data-astro-cid-xgvwrve7]{height:35rem}.pyric-example[data-astro-cid-2qfr4sn2]{margin:2rem 0}figcaption[data-astro-cid-2qfr4sn2]{margin-bottom:.75rem;font-weight:650}.pyric-example-grid[data-astro-cid-2qfr4sn2]{display:grid;grid-template-columns:minmax(0,1fr) minmax(19rem,.8fr);gap:1rem}pre[data-astro-cid-2qfr4sn2]{box-sizing:border-box;width:100%;min-height:19rem;margin:0;border:1px solid var(--border, #30303a);border-radius:.5rem}pre[data-astro-cid-2qfr4sn2]{overflow:auto;padding:1rem;background:#0f0f17;color:#e8e8ef}.pyric-showcase[data-astro-cid-2qfr4sn2] .pyric-example-grid[data-astro-cid-2qfr4sn2]{grid-template-columns:1fr}@media(max-width:800px){.pyric-example-grid[data-astro-cid-2qfr4sn2]{grid-template-columns:1fr}}.example-gallery[data-astro-cid-aiymqahz]{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,18rem),1fr));gap:1rem;margin:2rem 0}.example-card[data-astro-cid-aiymqahz]{display:block;border:1px solid var(--border);border-radius:.85rem;padding:1.15rem;background:var(--surface-1);color:inherit;text-decoration:none;transition:border-color .15s,transform .15s}.example-card[data-astro-cid-aiymqahz]:hover{border-color:var(--accent);transform:translateY(-2px)}.example-card[data-astro-cid-aiymqahz].is-showcase{grid-column:1 / -1;padding:clamp(1.25rem,3vw,2rem);background:radial-gradient(circle at 80% 10%,#463d7138,transparent 55%),var(--surface-1)}.example-card[data-astro-cid-aiymqahz]>span[data-astro-cid-aiymqahz]{color:var(--accent);font-size:.7rem;font-weight:750;letter-spacing:.08em;text-transform:uppercase}.example-card[data-astro-cid-aiymqahz] h2[data-astro-cid-aiymqahz]{margin:.45rem 0;font-size:1.2rem}.example-card[data-astro-cid-aiymqahz] p[data-astro-cid-aiymqahz]{margin:0 0 1rem;color:var(--muted)}.example-card[data-astro-cid-aiymqahz] code[data-astro-cid-aiymqahz]{font-size:.72rem}.example-header[data-astro-cid-3f5pqdpq]{margin:0 0 1.5rem}.example-header[data-astro-cid-3f5pqdpq] p[data-astro-cid-3f5pqdpq]{margin:0 0 .5rem;color:var(--muted);font-family:var(--font-mono);font-size:.7rem;font-weight:500;letter-spacing:.04em;text-transform:uppercase}.example-header[data-astro-cid-3f5pqdpq] h1[data-astro-cid-3f5pqdpq]{margin:0;color:var(--ink);font-size:clamp(1.75rem,3vw,2.35rem);font-weight:600;line-height:1.15;letter-spacing:-.025em}.example-header[data-astro-cid-3f5pqdpq] div[data-astro-cid-3f5pqdpq]{max-width:58ch;margin-top:.8rem;color:var(--muted);font-size:1rem;line-height:1.55}.source-explorer{overflow:hidden;border:1px solid var(--line);border-radius:.5rem;background:#111118}.source-toolbar{display:flex;align-items:center;justify-content:space-between;gap:1rem;padding:.7rem .8rem;border-bottom:1px solid #353540;color:#f4f4f7}.source-toolbar strong{font-size:.8rem}.source-toolbar button{border:1px solid #4a4a58;border-radius:.35rem;padding:.38rem .55rem;background:#24242f;color:#f4f4f7;cursor:pointer}.source-explorer pre{max-height:34rem;margin:0;overflow:auto;padding:1rem;background:#111118;color:#d9f99d;font:.76rem/1.55 JetBrains Mono,monospace}.example-doc-page[data-astro-cid-ghke3xma]{width:100%}.example-explanation[data-astro-cid-ghke3xma],.example-rules[data-astro-cid-ghke3xma]{max-width:72ch;margin-top:2.5rem}.example-rules[data-astro-cid-ghke3xma] h2[data-astro-cid-ghke3xma]{margin:0 0 .5rem;color:var(--ink);font-size:1.45rem}.example-rules[data-astro-cid-ghke3xma] p[data-astro-cid-ghke3xma]{margin:0 0 1rem;color:var(--muted);line-height:1.6}
@@ -1 +0,0 @@
1
- import{S as d}from"./app.bnmVTkIY.js";import"./jsx-runtime.D_zvdyIk.js";import"./index.DBy5LfQW.js";import"./sandbox-controls.C9Aaazt8.js";import"./reads.BYBRLbsE.js";import"./index.DzVde04M.js";import"./index.DNyk7q8W.js";export{d as StudioApp};
@@ -1 +0,0 @@
1
- import{e as o}from"./sandbox-controls.C9Aaazt8.js";function t(i={}){return o()}export{t as i};