@pulse-compute/cli 0.0.0 → 1.0.0-beta.1

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 (190) hide show
  1. package/API.md +539 -0
  2. package/CHANGELOG.md +47 -0
  3. package/README.md +70 -1
  4. package/bin/pulse.js +15 -0
  5. package/bin/pulsewasm-extract.js +22 -0
  6. package/cli-spec.json +575 -0
  7. package/completions/_pulse +106 -0
  8. package/completions/pulse.bash +31 -0
  9. package/completions/pulse.fish +76 -0
  10. package/docs/README.md +77 -0
  11. package/docs/architecture/current-contracts.md +381 -0
  12. package/docs/architecture/overview.md +93 -0
  13. package/docs/architecture/vision.md +515 -0
  14. package/docs/concepts/bodies.md +186 -0
  15. package/docs/concepts/compilation-and-lowering.md +496 -0
  16. package/docs/concepts/contracts-and-providers.md +158 -0
  17. package/docs/concepts/effects-and-continuations.md +243 -0
  18. package/docs/concepts/entities-and-adapters.md +71 -0
  19. package/docs/concepts/package-owned-lowering.md +175 -0
  20. package/docs/concepts/targets-and-hosts.md +62 -0
  21. package/docs/contributing/README.md +38 -0
  22. package/docs/contributing/adding-core-provider.md +315 -0
  23. package/docs/contributing/adding-first-party-lowerer.md +327 -0
  24. package/docs/contributing/entities-lowering.md +91 -0
  25. package/docs/contributing/package-lowerer-contract.md +383 -0
  26. package/docs/contributing/pulse-aware-packages.md +149 -0
  27. package/docs/examples.md +112 -0
  28. package/docs/fixtures/inspect-fetch-composition.selected.json +181 -0
  29. package/docs/getting-started.md +128 -0
  30. package/docs/guides/compatibility-imports.md +60 -0
  31. package/docs/guides/deploying-fastly.md +188 -0
  32. package/docs/guides/deploying-node.md +143 -0
  33. package/docs/guides/events.md +233 -0
  34. package/docs/guides/fastly-capabilities.md +153 -0
  35. package/docs/guides/fetching-and-composition.md +101 -0
  36. package/docs/guides/grip.md +94 -0
  37. package/docs/guides/json-schemas.md +233 -0
  38. package/docs/guides/migrating-from-express.md +192 -0
  39. package/docs/guides/project-lifecycle.md +143 -0
  40. package/docs/guides/routing.md +184 -0
  41. package/docs/guides/troubleshooting.md +47 -0
  42. package/docs/maintainers/README.md +60 -0
  43. package/docs/maintainers/codex-maintainer.md +71 -0
  44. package/docs/maintainers/documentation-deployment.md +147 -0
  45. package/docs/maintainers/documentation-system.md +58 -0
  46. package/docs/maintainers/documentation-versioning.md +65 -0
  47. package/docs/maintainers/maintainer-charter.md +84 -0
  48. package/docs/maintainers/maintenance-policy.json +778 -0
  49. package/docs/maintainers/maintenance-policy.md +124 -0
  50. package/docs/maintainers/npm-publishing.md +154 -0
  51. package/docs/maintainers/plugin-readiness.json +19 -0
  52. package/docs/maintainers/plugin-readiness.md +31 -0
  53. package/docs/maintainers/public-site.md +158 -0
  54. package/docs/maintainers/release-acceptance.md +250 -0
  55. package/docs/maintainers/release-manifest.md +88 -0
  56. package/docs/maintainers/repository-setup.md +145 -0
  57. package/docs/maintainers/scope-policy.md +93 -0
  58. package/docs/maintainers/support-and-triage.md +74 -0
  59. package/docs/maintainers/testing.md +288 -0
  60. package/docs/packages/README.md +59 -0
  61. package/docs/packages/assets.md +85 -0
  62. package/docs/packages/cli.md +190 -0
  63. package/docs/packages/crypto.md +71 -0
  64. package/docs/packages/entities.md +129 -0
  65. package/docs/packages/grip.md +82 -0
  66. package/docs/packages/implementation-packages.md +113 -0
  67. package/docs/packages/jwt.md +55 -0
  68. package/docs/packages/provider-fastly.md +217 -0
  69. package/docs/packages/pulse.md +159 -0
  70. package/docs/packages/runtime.md +256 -0
  71. package/docs/preview-scope.md +142 -0
  72. package/docs/reference/README.md +33 -0
  73. package/docs/reference/cli-spec.json +575 -0
  74. package/docs/reference/cli.md +457 -0
  75. package/docs/reference/compatibility-matrix.md +169 -0
  76. package/docs/reference/diagnostics.md +1872 -0
  77. package/docs/reference/documentation-versions.json +14 -0
  78. package/docs/reference/environment.md +347 -0
  79. package/docs/reference/handler-authoring.md +264 -0
  80. package/docs/reference/project-config.md +554 -0
  81. package/docs/reference/project-config.schema.json +918 -0
  82. package/docs/reference/release-manifest.json +427 -0
  83. package/docs/reference/shell-completion.md +23 -0
  84. package/documentation-site.json +661 -0
  85. package/documentation-versions.json +14 -0
  86. package/examples/01-hello-json/.pulse/.gitignore +3 -0
  87. package/examples/01-hello-json/.pulse/config.ts +16 -0
  88. package/examples/01-hello-json/README.md +119 -0
  89. package/examples/01-hello-json/package.json +20 -0
  90. package/examples/01-hello-json/src/index.ts +9 -0
  91. package/examples/01-hello-json/tests/pulse.harness.ts +22 -0
  92. package/examples/01-hello-json/tsconfig.json +14 -0
  93. package/examples/02-request-schema/.pulse/.gitignore +3 -0
  94. package/examples/02-request-schema/.pulse/config.ts +17 -0
  95. package/examples/02-request-schema/README.md +145 -0
  96. package/examples/02-request-schema/package.json +20 -0
  97. package/examples/02-request-schema/src/index.ts +18 -0
  98. package/examples/02-request-schema/src/schemas.ts +20 -0
  99. package/examples/02-request-schema/tests/pulse.harness.ts +37 -0
  100. package/examples/02-request-schema/tsconfig.json +14 -0
  101. package/examples/03-fetch-composition/.pulse/.gitignore +3 -0
  102. package/examples/03-fetch-composition/.pulse/config.ts +31 -0
  103. package/examples/03-fetch-composition/README.md +210 -0
  104. package/examples/03-fetch-composition/package.json +20 -0
  105. package/examples/03-fetch-composition/src/index.ts +60 -0
  106. package/examples/03-fetch-composition/tests/pulse.harness.ts +47 -0
  107. package/examples/03-fetch-composition/tsconfig.json +14 -0
  108. package/examples/05-fastly-capabilities/.pulse/.gitignore +3 -0
  109. package/examples/05-fastly-capabilities/.pulse/config.ts +57 -0
  110. package/examples/05-fastly-capabilities/README.md +257 -0
  111. package/examples/05-fastly-capabilities/package.json +22 -0
  112. package/examples/05-fastly-capabilities/src/index.ts +55 -0
  113. package/examples/05-fastly-capabilities/tests/pulse.harness.ts +66 -0
  114. package/examples/05-fastly-capabilities/tsconfig.json +14 -0
  115. package/examples/07-opaque-proxy/.pulse/.gitignore +3 -0
  116. package/examples/07-opaque-proxy/.pulse/config.ts +38 -0
  117. package/examples/07-opaque-proxy/README.md +150 -0
  118. package/examples/07-opaque-proxy/package.json +21 -0
  119. package/examples/07-opaque-proxy/src/index.ts +9 -0
  120. package/examples/07-opaque-proxy/tests/pulse.harness.ts +25 -0
  121. package/examples/07-opaque-proxy/tsconfig.json +14 -0
  122. package/examples/09-router-lowering/.pulse/.gitignore +3 -0
  123. package/examples/09-router-lowering/.pulse/config.ts +22 -0
  124. package/examples/09-router-lowering/README.md +287 -0
  125. package/examples/09-router-lowering/package.json +22 -0
  126. package/examples/09-router-lowering/src/index.ts +65 -0
  127. package/examples/09-router-lowering/tests/pulse.harness.ts +91 -0
  128. package/examples/09-router-lowering/tsconfig.json +14 -0
  129. package/examples/10-entities-tools/.pulse/.gitignore +4 -0
  130. package/examples/10-entities-tools/.pulse/config.ts +23 -0
  131. package/examples/10-entities-tools/README.md +165 -0
  132. package/examples/10-entities-tools/package.json +21 -0
  133. package/examples/10-entities-tools/src/handlers.ts +15 -0
  134. package/examples/10-entities-tools/src/index.ts +31 -0
  135. package/examples/10-entities-tools/src/schemas.ts +18 -0
  136. package/examples/10-entities-tools/tests/pulse.harness.ts +40 -0
  137. package/examples/10-entities-tools/tools-facade.cjs +158 -0
  138. package/examples/10-entities-tools/tsconfig.json +14 -0
  139. package/examples/11-events/.pulse/.gitignore +4 -0
  140. package/examples/11-events/.pulse/config.ts +24 -0
  141. package/examples/11-events/README.md +194 -0
  142. package/examples/11-events/package.json +20 -0
  143. package/examples/11-events/src/index.ts +27 -0
  144. package/examples/11-events/src/schemas.ts +19 -0
  145. package/examples/11-events/tests/pulse.harness.ts +34 -0
  146. package/examples/11-events/tsconfig.json +15 -0
  147. package/examples/12-mcp-proxy/.pulse/.gitignore +3 -0
  148. package/examples/12-mcp-proxy/.pulse/config.ts +25 -0
  149. package/examples/12-mcp-proxy/README.md +149 -0
  150. package/examples/12-mcp-proxy/package.json +20 -0
  151. package/examples/12-mcp-proxy/src/index.ts +17 -0
  152. package/examples/12-mcp-proxy/tests/pulse.harness.ts +29 -0
  153. package/examples/12-mcp-proxy/tsconfig.json +14 -0
  154. package/examples/13-jwt-es256/.pulse/config.ts +19 -0
  155. package/examples/13-jwt-es256/README.md +195 -0
  156. package/examples/13-jwt-es256/package.json +21 -0
  157. package/examples/13-jwt-es256/src/index.ts +21 -0
  158. package/examples/13-jwt-es256/tests/pulse.harness.ts +54 -0
  159. package/examples/13-jwt-es256/tsconfig.json +14 -0
  160. package/examples/README.md +36 -0
  161. package/package.json +66 -6
  162. package/project-config.schema.json +918 -0
  163. package/release-manifest.json +427 -0
  164. package/src/command-spec.js +279 -0
  165. package/src/completion.js +113 -0
  166. package/src/diagnostics.js +350 -0
  167. package/src/documentation.js +45 -0
  168. package/src/index.d.ts +133 -0
  169. package/src/index.js +15 -0
  170. package/src/internal/command-executor.d.ts +29 -0
  171. package/src/internal/command-executor.js +143 -0
  172. package/src/internal/command-plan.d.ts +9 -0
  173. package/src/internal/command-plan.js +73 -0
  174. package/src/internal/command-reporter.d.ts +15 -0
  175. package/src/internal/command-reporter.js +133 -0
  176. package/src/internal/command-request.d.ts +35 -0
  177. package/src/internal/command-request.js +154 -0
  178. package/src/internal/node-http.js +54 -0
  179. package/src/internal/project-context.d.ts +66 -0
  180. package/src/internal/project-context.js +175 -0
  181. package/src/project-config-reference.js +4 -0
  182. package/src/project-config-schema.d.ts +23 -0
  183. package/src/project-config-schema.js +271 -0
  184. package/src/project-config.js +724 -0
  185. package/src/project-execution.js +2930 -0
  186. package/src/provider-drivers.js +3 -0
  187. package/src/target-support.js +3 -0
  188. package/src/typescript-module-loader.js +269 -0
  189. package/src/workflow.js +78 -0
  190. package/src/workspace.js +82 -0
@@ -0,0 +1,2930 @@
1
+ 'use strict';
2
+
3
+ const assert = require('node:assert/strict');
4
+ const crypto = require('node:crypto');
5
+ const fs = require('node:fs');
6
+ const http = require('node:http');
7
+ const path = require('node:path');
8
+ const { once } = require('node:events');
9
+ const {
10
+ loadCanonicalModule,
11
+ writeCanonicalBuild
12
+ } = require('@pulse-compute/wasm-compiler/canonical-api-compiler');
13
+ const {
14
+ compileCanonicalProject,
15
+ packageRealizationArtifactsForCompiled
16
+ } = require('@pulse-compute/wasm-compiler/canonical-project-compiler');
17
+ const { createCanonicalSchemaCodecs } = require('@pulse-compute/wasm-schema-json/compiler/canonical-schema-codecs');
18
+ const { buildJavascriptApplicationPlan } = require('@pulse-compute/wasm-compiler/javascript-application-plan');
19
+ const { buildCanonicalNativePlan } = require('@pulse-compute/wasm-compiler/canonical-native-plan');
20
+ const {
21
+ compileCanonicalNativePlan,
22
+ writeCanonicalNativeModule
23
+ } = require('@pulse-compute/wasm-compiler/canonical-native-compiler');
24
+ const {
25
+ executeCanonicalNativeModule
26
+ } = require('@pulse-compute/wasm-host-runtime/runtime/canonical-native-host');
27
+ const { PulseProjectError, projectJson, relative } = require('./project-config.js');
28
+ const { describeDiagnostic, decorateDiagnostic, httpStatusForDiagnostic } = require('./diagnostics.js');
29
+ const {
30
+ getProviderDriver,
31
+ getProviderTargetDescriptor,
32
+ getProviderTargetSupportDeclaration,
33
+ providerTargetAvailability,
34
+ providerIds
35
+ } = require('./provider-drivers.js');
36
+ const {
37
+ buildJavascriptTargetSupportEvidence,
38
+ buildEventTargetSupportEvidence
39
+ } = require('./target-support.js');
40
+ const eventContracts = require(path.join(
41
+ path.dirname(require.resolve('@pulse-compute/wasm-contracts')),
42
+ 'events',
43
+ 'contracts.js'
44
+ ));
45
+ const {
46
+ PROVIDER_TARGET_INVOCATION_VERSION,
47
+ PROVIDER_PLAN_INPUT_VERSION,
48
+ createProviderNativeArtifact,
49
+ createProviderPlanInput,
50
+ createProviderTargetInvocation,
51
+ normalizeProviderTargetResult,
52
+ projectProviderRequirements
53
+ } = require('@pulse-compute/wasm-contracts/provider/toolchain');
54
+ const { loadJavascriptApplication } = require('./typescript-module-loader.js');
55
+ const { writeNodeHttpResponse } = require('./internal/node-http.js');
56
+ const {
57
+ HANDLER_AUTHORING_MODES
58
+ } = require('@pulse-compute/wasm-contracts/handler/surface-contract');
59
+ const {
60
+ CANONICAL_PACKAGE_INSPECTION_VERSION
61
+ } = require('@pulse-compute/wasm-contracts/package/package-contract');
62
+
63
+ const PROJECT_EXECUTION_VERSION = 'pulse.project-execution.v10';
64
+ const EVENT_INSPECTION_VERSION = 'pulse.event-inspection.v1';
65
+ const BUILD_MANIFEST = 'pulse-build.json';
66
+ const COMPILE_MANIFEST = 'pulse-compile.json';
67
+ const cliPackageVersion = require('../package.json').version;
68
+ const releaseCatalog = require('../release-manifest.json');
69
+ const releaseNode = releaseCatalog.publication;
70
+
71
+ function nodeVersionSatisfiesEngines(version, engines) {
72
+ const actual = /^(\d+)\.(\d+)\.(\d+)$/.exec(String(version));
73
+ if (!actual) return false;
74
+ const actualParts = actual.slice(1).map((part) => Number.parseInt(part, 10));
75
+ return String(engines).split(/\s*\|\|\s*/).some((range) => {
76
+ const minimum = /^\^(\d+)\.(\d+)\.(\d+)$/.exec(range);
77
+ if (!minimum) return false;
78
+ const minimumParts = minimum.slice(1).map((part) => Number.parseInt(part, 10));
79
+ if (actualParts[0] !== minimumParts[0]) return false;
80
+ for (let index = 1; index < 3; index += 1) {
81
+ if (actualParts[index] !== minimumParts[index]) return actualParts[index] > minimumParts[index];
82
+ }
83
+ return true;
84
+ });
85
+ }
86
+
87
+ function stableJson(value) {
88
+ return `${JSON.stringify(value, null, 2)}\n`;
89
+ }
90
+
91
+ function writePackageInspectionArtifacts(compiled, outDir) {
92
+ const inspection = compiled && compiled.packageInspection;
93
+ const artifacts = inspection && Array.isArray(inspection.artifacts) ? inspection.artifacts : [];
94
+ const files = artifacts.map((artifact) => {
95
+ const relativeFile = String(artifact.file || '').replace(/\\/g, '/');
96
+ const target = path.resolve(outDir, relativeFile);
97
+ const relativeTarget = path.relative(path.resolve(outDir), target);
98
+ if (!relativeFile || relativeTarget.startsWith('..') || path.isAbsolute(relativeTarget)) {
99
+ throw new PulseProjectError(
100
+ 'PULSE_PACKAGE_INSPECTION_ARTIFACT_UNSAFE',
101
+ `Package inspection artifact ${artifact.id || '<unknown>'} must remain inside the build output.`,
102
+ { id: artifact.id, file: relativeFile }
103
+ );
104
+ }
105
+ fs.mkdirSync(path.dirname(target), { recursive: true });
106
+ const bytes = stableJson(artifact.data);
107
+ fs.writeFileSync(target, bytes);
108
+ return Object.freeze({
109
+ id: artifact.id,
110
+ contractId: artifact.contractId,
111
+ kind: artifact.kind,
112
+ mediaType: artifact.mediaType,
113
+ file: relativeFile,
114
+ path: target,
115
+ sha256: crypto.createHash('sha256').update(bytes).digest('hex')
116
+ });
117
+ });
118
+ return Object.freeze({
119
+ version: inspection && inspection.version || CANONICAL_PACKAGE_INSPECTION_VERSION,
120
+ artifacts: Object.freeze(files),
121
+ summary: inspection && inspection.summary || Object.freeze({ packages: 0, artifacts: 0, declaredHandlers: 0, handlerEffects: 0 })
122
+ });
123
+ }
124
+
125
+ function packageInspectionManifest(written) {
126
+ return Object.freeze({
127
+ version: written.version,
128
+ artifacts: Object.freeze(written.artifacts.map((artifact) => Object.freeze({
129
+ id: artifact.id,
130
+ contractId: artifact.contractId,
131
+ kind: artifact.kind,
132
+ mediaType: artifact.mediaType,
133
+ file: artifact.file,
134
+ sha256: artifact.sha256
135
+ }))),
136
+ summary: written.summary
137
+ });
138
+ }
139
+
140
+ function selectedEventTargetSupport(project, compiled, descriptor = targetDescriptor(project)) {
141
+ const driver = providerDriver(project);
142
+ return buildEventTargetSupportEvidence(compiled, {
143
+ provider: project.provider,
144
+ target: project.target || 'native',
145
+ descriptor,
146
+ eventTestTargets: driver.events && driver.events.targets || []
147
+ });
148
+ }
149
+
150
+ function sortedUnique(values) {
151
+ return Object.freeze([...new Set((values || []).filter((value) => value !== null && value !== undefined).map(String))].sort());
152
+ }
153
+
154
+ function eventInspectionProjection(project, compiled, support = selectedEventTargetSupport(project, compiled)) {
155
+ if (!support) return null;
156
+ const catalog = compiled.eventCatalog || compiled.metadata && compiled.metadata.events && compiled.metadata.events.catalog;
157
+ const outbound = compiled.eventOutboundRequirements || Object.freeze({
158
+ version: compiled.metadata.events.outboundRequirementsVersion,
159
+ callsites: Object.freeze([]),
160
+ capabilities: Object.freeze([]),
161
+ hostRequirements: Object.freeze([]),
162
+ summary: Object.freeze({ callsites: 0, schemaBound: 0, noPayload: 0, grouped: 0, handlers: 0 })
163
+ });
164
+ const registrations = catalog && catalog.events || [];
165
+ const callsites = outbound.callsites || [];
166
+ const capabilities = sortedUnique([
167
+ ...registrations.flatMap((event) => event.capabilities || []),
168
+ ...(outbound.capabilities || [])
169
+ ]);
170
+ const hostRequirements = sortedUnique([
171
+ ...registrations.flatMap((event) => event.hostRequirements || []),
172
+ ...(outbound.hostRequirements || [])
173
+ ]);
174
+ return Object.freeze({
175
+ version: EVENT_INSPECTION_VERSION,
176
+ contractId: eventContracts.EVENT_CONTRACT_ID,
177
+ catalog,
178
+ outboundRequirements: outbound,
179
+ registrations: Object.freeze(registrations),
180
+ callsites: Object.freeze(callsites),
181
+ schemas: Object.freeze({
182
+ registrations: sortedUnique(registrations.map((event) => event.schemaId)),
183
+ emissions: sortedUnique(callsites.map((callsite) => callsite.schemaId)),
184
+ all: sortedUnique([
185
+ ...registrations.map((event) => event.schemaId),
186
+ ...callsites.map((callsite) => callsite.schemaId)
187
+ ])
188
+ }),
189
+ capabilities,
190
+ hostRequirements,
191
+ targetSupport: support,
192
+ policy: Object.freeze({
193
+ providerNeutralCatalog: true,
194
+ publicInjectionCommand: false,
195
+ automaticLoopback: false,
196
+ automaticFallback: false
197
+ })
198
+ });
199
+ }
200
+
201
+ function writeEventInspectionArtifacts(project, compiled, outDir, support) {
202
+ const inspection = eventInspectionProjection(project, compiled, support);
203
+ if (!inspection) return null;
204
+ const catalogFile = path.join(outDir, 'event-catalog.json');
205
+ const inspectionFile = path.join(outDir, 'event-inspection.json');
206
+ fs.writeFileSync(catalogFile, stableJson(inspection.catalog));
207
+ fs.writeFileSync(inspectionFile, stableJson(inspection));
208
+ return Object.freeze({
209
+ inspection,
210
+ catalogFile,
211
+ inspectionFile,
212
+ files: Object.freeze({ catalog: path.basename(catalogFile), inspection: path.basename(inspectionFile) })
213
+ });
214
+ }
215
+
216
+ function eventManifestProjection(written) {
217
+ return written ? Object.freeze({ ...written.inspection, files: written.files }) : undefined;
218
+ }
219
+
220
+ function assertEventCommandEligible(project, compiled, command, descriptor = targetDescriptor(project)) {
221
+ const support = selectedEventTargetSupport(project, compiled, descriptor);
222
+ if (!support) return null;
223
+ const commandSupport = support.commands.find((entry) => entry.id === command);
224
+ if (!commandSupport || commandSupport.status !== 'eligible') {
225
+ const code = support.diagnosticCode || 'PULSE_EVENT_TARGET_UNSUPPORTED';
226
+ throw new PulseProjectError(
227
+ code,
228
+ `pulse ${command} cannot realize the event plane for ${project.provider}/${project.target || 'native'}.`,
229
+ {
230
+ provider: project.provider,
231
+ target: project.target || 'native',
232
+ command,
233
+ eventTargetSupport: support,
234
+ automaticFallback: false
235
+ }
236
+ );
237
+ }
238
+ return support;
239
+ }
240
+
241
+ function projectPlanInspection(project, compiled) {
242
+ const profile = project.selectedProfile || project.profile || null;
243
+ return Object.freeze({
244
+ mode: 'conventional',
245
+ workspace: project.workspace ? Object.freeze({
246
+ root: project.workspace.root,
247
+ configFile: project.workspace.configFile,
248
+ source: project.workspace.source
249
+ }) : null,
250
+ projectHash: project.projectHash,
251
+ planHash: project.planHash,
252
+ selectedProfile: profile ? Object.freeze({
253
+ name: profile.name,
254
+ source: profile.source,
255
+ host: profile.host,
256
+ target: profile.target,
257
+ reporting: profile.reporting,
258
+ reportingLevel: project.reportingLevel
259
+ }) : null,
260
+ strict: project.strict !== false,
261
+ bindings: Object.freeze({
262
+ config: Object.freeze([...(project.bindings && project.bindings.config || [])]),
263
+ secret: Object.freeze([...(project.bindings && project.bindings.secret || [])])
264
+ }),
265
+ fragments: Object.freeze({
266
+ keys: Object.freeze(Object.keys(project.fragments || {}).sort()),
267
+ ownership: compiled && compiled.packageProduct
268
+ ? compiled.packageProduct.fragments
269
+ : Object.freeze([]),
270
+ unclaimed: compiled && compiled.packageProduct
271
+ ? Object.freeze(compiled.packageProduct.fragments.filter((entry) => entry.present && !entry.contractId).map((entry) => entry.key))
272
+ : Object.freeze(Object.keys(project.fragments || {}).sort())
273
+ }),
274
+ crypto: Object.freeze({
275
+ declaration: project.profilePlan && project.profilePlan.crypto || null,
276
+ realizationPlan: compiled && compiled.cryptoRealizationPlan || null
277
+ }),
278
+ application: compiled && (compiled.application || compiled.metadata && compiled.metadata.application) || null
279
+ });
280
+ }
281
+
282
+ function jsonPolicyInspection(project, compiled, nativePlan) {
283
+ const policy = compiled && compiled.metadata && compiled.metadata.json;
284
+ return Object.freeze({
285
+ strict: project.strict !== false,
286
+ schemaBoundRequestCount: Number(policy && policy.schemaBoundRequestCount || 0),
287
+ genericRequestCount: Number(policy && policy.genericRequestCount || 0),
288
+ genericParserRequired: Boolean(policy && policy.genericParserRequired),
289
+ maxBytes: Number(policy && policy.maxBytes || project.schemas && project.schemas.maxBytes || 65536),
290
+ native: nativePlan && nativePlan.json || null
291
+ });
292
+ }
293
+
294
+ function compileProject(project, options = {}) {
295
+ const handlerAuthoring = options.handlerAuthoring || HANDLER_AUTHORING_MODES.ASYNC_REQUIRED;
296
+ const configuredTarget = project.target || 'native';
297
+ const packageTargetDescriptor = getProviderTargetDescriptor(providerDriver(project), configuredTarget);
298
+ return compileCanonicalProject(project.entryFile, {
299
+ rootDir: project.root,
300
+ // Package lowerers are discovered from the nearest package-manager workspace.
301
+ // The Pulse project root remains authoritative for config and paths, but a
302
+ // conventional project may live inside a larger source workspace.
303
+ workspaceRoot: undefined,
304
+ configFile: project.configFile,
305
+ schemas: project.schemas,
306
+ strict: project.strict !== false,
307
+ emitJsonPolicy: true,
308
+ handlerAuthoring,
309
+ requireAsync: handlerAuthoring === HANDLER_AUTHORING_MODES.ASYNC_REQUIRED,
310
+ requireEffectAwait: false,
311
+ nativeEligibilityMode: (project.target || 'native') === 'javascript' ? 'record' : 'enforce',
312
+ packageTargetDescriptor,
313
+ packageTarget: configuredTarget,
314
+ applicationProjectMetadata: Object.freeze({
315
+ constructionMode: 'auto',
316
+ projectHash: project.projectHash,
317
+ configPlanHash: project.planHash,
318
+ selectedProfile: project.profile,
319
+ strict: project.strict !== false,
320
+ bindings: project.bindings,
321
+ fragments: project.fragments,
322
+ crypto: project.profilePlan && project.profilePlan.crypto,
323
+ reporting: project.reporting,
324
+ reportingLevel: project.reportingLevel,
325
+ target: project.target || 'native',
326
+ host: project.provider || null
327
+ })
328
+ });
329
+ }
330
+
331
+ function compileNativeProjectInMemory(project, options = {}) {
332
+ const compiled = options.compiled || compileProject(project);
333
+ const plan = buildCanonicalNativePlan(compiled, { reporting: project.reporting });
334
+ const native = compileCanonicalNativePlan(plan, {
335
+ cwd: project.root,
336
+ projectRoot: project.root,
337
+ profile: project.selectedProfile && project.selectedProfile.name || project.profile && project.profile.name || 'native',
338
+ targetDescriptor: getProviderTargetDescriptor(providerDriver(project), 'native'),
339
+ synchronizedPackages: releaseCatalog.packages.map(({ name, version }) => Object.freeze({ name, version })),
340
+ timeoutMs: options.timeoutMs,
341
+ nativeOptimization: options.experimentalNativeSize === true
342
+ ? 'experimental-native-size'
343
+ : options.nativeOptimization
344
+ });
345
+ return Object.freeze({ compiled, plan, native });
346
+ }
347
+
348
+ function providerDriver(project) {
349
+ return getProviderDriver(project.providerSelector || project.provider, {
350
+ projectRoot: project.root
351
+ });
352
+ }
353
+
354
+ function targetDescriptor(project, target = project.target || 'native') {
355
+ return Object.freeze({
356
+ ...getProviderTargetDescriptor(providerDriver(project), target),
357
+ resolvedReporting: project.reportingPolicy
358
+ });
359
+ }
360
+
361
+ function selectedProviderTarget(project, target = project.target || 'native') {
362
+ return getProviderTargetDescriptor(providerDriver(project), target);
363
+ }
364
+
365
+ function assertImplementedTarget(project, command) {
366
+ const target = project.target || 'native';
367
+ const descriptor = targetDescriptor(project, target);
368
+ if (!descriptor.commands || descriptor.commands[command] !== true) {
369
+ throw new PulseProjectError(
370
+ 'PULSE_TARGET_IMPLEMENTATION_PENDING',
371
+ `pulse ${command} cannot realize the selected ${target} target yet.`,
372
+ {
373
+ target,
374
+ command,
375
+ provider: project.provider,
376
+ selectedProfile: project.profile,
377
+ supportedCommands: Object.freeze(Object.entries(descriptor.commands || {}).filter(([, supported]) => supported).map(([name]) => name)),
378
+ targetDescriptor: descriptor,
379
+ targetSupport: getProviderTargetSupportDeclaration(providerDriver(project), target),
380
+ automaticFallback: false
381
+ }
382
+ );
383
+ }
384
+ return descriptor;
385
+ }
386
+
387
+ function javascriptLoadFailure(error) {
388
+ if (!error) return null;
389
+ return Object.freeze({
390
+ name: error.name ? String(error.name) : 'Error',
391
+ code: error.code ? String(error.code) : null,
392
+ message: error.message ? String(error.message) : String(error),
393
+ detail: error.detail && typeof error.detail === 'object' ? Object.freeze({ ...error.detail }) : null,
394
+ diagnostics: Array.isArray(error.diagnostics) ? Object.freeze([...error.diagnostics]) : Object.freeze([])
395
+ });
396
+ }
397
+
398
+ function prepareJavascriptApplication(project, options = {}) {
399
+ const descriptor = targetDescriptor(project, 'javascript');
400
+ const javascript = providerDriver(project).javascript;
401
+ const plan = buildJavascriptApplicationPlan(project.entryFile, {
402
+ rootDir: project.root,
403
+ workspaceRoot: undefined,
404
+ configFile: project.configFile,
405
+ projectFragments: project.fragments,
406
+ provider: project.provider,
407
+ targetId: descriptor.targetId,
408
+ providerLifecycleDeferred: descriptor.lifecycle !== true,
409
+ capabilityEnvelope: descriptor.capabilities || Object.freeze({
410
+ version: 'pulse.javascript-capability-envelope.v1',
411
+ provider: project.provider,
412
+ status: descriptor.requestAdapter === true ? 'request-lifecycle-ready' : 'provider-adapters-deferred',
413
+ core: Object.freeze({ request: descriptor.requestAdapter === true, response: descriptor.requestAdapter === true, state: true }),
414
+ effects: Object.freeze({ fetch: false, config: false, secret: false, kv: false }),
415
+ packages: Object.freeze([])
416
+ })
417
+ });
418
+ let loaded = null;
419
+ let loadError = null;
420
+ let loadAttempted = false;
421
+ let loadSkippedReason = null;
422
+ const localEmulation = options.localEmulation === true && javascript && javascript.localEmulation === true;
423
+ if (descriptor.applicationLoader === true && javascript && (javascript.validateApplication || (localEmulation && javascript.loadApplication))) {
424
+ if (options.load === false) {
425
+ loadSkippedReason = 'plan-only-evidence';
426
+ } else if (options.captureLoadError === true && plan.loadable !== true) {
427
+ loadSkippedReason = 'application-plan-not-loadable';
428
+ } else {
429
+ loadAttempted = true;
430
+ try {
431
+ loaded = localEmulation && javascript.loadApplication
432
+ ? javascript.loadApplication(plan, {
433
+ projectRoot: project.root,
434
+ schemaBundle: options.schemaBundle
435
+ })
436
+ : loadJavascriptApplication(plan, {
437
+ workspaceRoot: project.root,
438
+ validateApplication: javascript.validateApplication,
439
+ allowedPackages: options.allowedPackages
440
+ });
441
+ } catch (error) {
442
+ if (options.captureLoadError !== true) throw error;
443
+ loadError = javascriptLoadFailure(error);
444
+ }
445
+ }
446
+ } else if (descriptor.applicationLoader === true && javascript && javascript.buildTimeLoader === true) {
447
+ loadSkippedReason = 'provider-build-time-bundle-loader';
448
+ } else {
449
+ loadSkippedReason = 'provider-application-loader-unavailable';
450
+ }
451
+ return Object.freeze({ descriptor, plan, loaded, loadError, loadAttempted, loadSkippedReason });
452
+ }
453
+
454
+ function selectedTargetSupportEvidence(project, compiled, javascriptApplication, descriptor, options = {}) {
455
+ if ((project.target || 'native') !== 'javascript') return null;
456
+ const javascript = providerDriver(project).javascript;
457
+ const policy = javascript && javascript.targetSupportPolicy;
458
+ if (!policy) return null;
459
+ return buildJavascriptTargetSupportEvidence(project, {
460
+ compiled,
461
+ javascriptApplication,
462
+ descriptor: descriptor || javascriptApplication && javascriptApplication.descriptor,
463
+ declaration: options.targetSupportDeclaration
464
+ }, policy);
465
+ }
466
+
467
+ function assertExecutableProvider(project, command) {
468
+ const driver = providerDriver(project);
469
+ if (!driver.executable) {
470
+ throw new PulseProjectError(
471
+ command === 'test' ? 'PULSE_TEST_PROVIDER_REQUIRED' : 'PULSE_DEV_PROVIDER_UNSUPPORTED',
472
+ `pulse ${command} requires an executable provider.`,
473
+ { provider: project.provider, supported: providerIds({ executable: true }) }
474
+ );
475
+ }
476
+ return driver;
477
+ }
478
+
479
+ function providerExecutionOptions(project, values = {}) {
480
+ const driver = providerDriver(project);
481
+ const resolved = { ...values, reporting: project.reporting };
482
+ return driver.executionOptions ? driver.executionOptions(project.providerConfig, resolved) : resolved;
483
+ }
484
+
485
+ function requiresExactNativeCrypto(compiled) {
486
+ return Boolean(
487
+ compiled
488
+ && compiled.cryptoRealizationPlan
489
+ && Array.isArray(compiled.cryptoRealizationPlan.algorithms)
490
+ && compiled.cryptoRealizationPlan.algorithms.some((entry) => entry.kind === 'guest-linked')
491
+ );
492
+ }
493
+
494
+ function providerLoweringPlan(project, metadata) {
495
+ const driver = providerDriver(project);
496
+ if (typeof driver.createLoweringPlan === 'function') {
497
+ const input = createProviderPlanInput({
498
+ version: PROVIDER_PLAN_INPUT_VERSION,
499
+ capabilities: metadata && metadata.capabilities || [],
500
+ providerOperations: metadata && metadata.providerOperations || [],
501
+ opaqueReturnCount: metadata && metadata.opaqueReturnCount || 0
502
+ });
503
+ return driver.createLoweringPlan(input, project.providerConfig);
504
+ }
505
+ return Object.freeze({
506
+ version: 'pulse.canonical-provider-plan.v1',
507
+ contractVersion: 'pulse.canonical-provider-contract.v1',
508
+ provider: 'none',
509
+ providerVersion: 'internal',
510
+ package: '',
511
+ runtime: '',
512
+ buildTarget: 'portable-native-wasm',
513
+ deployable: false,
514
+ localExecution: false,
515
+ requirements: Object.freeze([]),
516
+ bindings: Object.freeze({}),
517
+ operations: Object.freeze([]),
518
+ providerSpecificUserland: false,
519
+ providerSdkUserland: false,
520
+ capabilityDiscoveryFromUserland: false
521
+ });
522
+ }
523
+
524
+ function synchronizedPackageFacts() {
525
+ return Object.freeze(releaseCatalog.packages.map(
526
+ ({ name, version }) => Object.freeze({ name, version })
527
+ ));
528
+ }
529
+
530
+ function selectedProfileName(project) {
531
+ return project.selectedProfile && project.selectedProfile.name
532
+ || project.profile && project.profile.name
533
+ || 'native';
534
+ }
535
+
536
+ function providerTargetInvocation(project, action, applicationPlan, providerPlan, options = {}) {
537
+ const nativeArtifact = options.native ? createProviderNativeArtifact(options.native) : null;
538
+ return createProviderTargetInvocation({
539
+ version: PROVIDER_TARGET_INVOCATION_VERSION,
540
+ action,
541
+ provider: project.provider,
542
+ selectedTarget: selectedProviderTarget(project, action.endsWith('javascript') ? 'javascript' : 'native'),
543
+ applicationPlan,
544
+ providerPlan,
545
+ providerConfig: project.providerConfig,
546
+ requirements: projectProviderRequirements(applicationPlan, providerPlan),
547
+ nativeArtifact,
548
+ javascript: options.javascript || null,
549
+ project: Object.freeze({
550
+ root: project.root,
551
+ outDir: options.outDir || null,
552
+ profile: selectedProfileName(project)
553
+ }),
554
+ synchronizedPackages: synchronizedPackageFacts(),
555
+ optimization: options.optimization,
556
+ timeoutMs: options.timeoutMs
557
+ });
558
+ }
559
+
560
+ function canonicalFuturePath(candidate) {
561
+ const requested = path.resolve(candidate);
562
+ const suffix = [];
563
+ let existing = requested;
564
+
565
+ while (!fs.existsSync(existing)) {
566
+ const parent = path.dirname(existing);
567
+ if (parent === existing) break;
568
+ suffix.unshift(path.basename(existing));
569
+ existing = parent;
570
+ }
571
+
572
+ return Object.freeze({
573
+ requested,
574
+ existing,
575
+ target: path.resolve(fs.realpathSync(existing), ...suffix)
576
+ });
577
+ }
578
+
579
+ function resolveOutputDirectory(project, outDir) {
580
+ const projectRoot = fs.realpathSync(path.resolve(project.root));
581
+ const requestedTarget = path.isAbsolute(outDir)
582
+ ? path.resolve(outDir)
583
+ : path.resolve(projectRoot, outDir);
584
+
585
+ const physical = canonicalFuturePath(requestedTarget);
586
+ const target = physical.target;
587
+ const relativeTarget = path.relative(projectRoot, target);
588
+
589
+ if (
590
+ !relativeTarget
591
+ || relativeTarget.startsWith('..')
592
+ || path.isAbsolute(relativeTarget)
593
+ ) {
594
+ throw new PulseProjectError(
595
+ 'PULSE_BUILD_OUT_UNSAFE',
596
+ `Pulse build output must be a child directory of the project root: ${requestedTarget}`,
597
+ { outDir: requestedTarget, projectRoot }
598
+ );
599
+ }
600
+
601
+ let current = physical.existing;
602
+
603
+ for (;;) {
604
+ if (fs.lstatSync(current).isSymbolicLink()) {
605
+ throw new PulseProjectError(
606
+ 'PULSE_BUILD_OUT_UNSAFE',
607
+ `Pulse build output must not traverse a symbolic link: ${current}`,
608
+ { outDir: requestedTarget, projectRoot, symbolicLink: current }
609
+ );
610
+ }
611
+
612
+ if (fs.realpathSync(current) === projectRoot) break;
613
+
614
+ const parent = path.dirname(current);
615
+ if (parent === current) {
616
+ throw new PulseProjectError(
617
+ 'PULSE_BUILD_OUT_UNSAFE',
618
+ `Pulse build output resolves outside the project root: ${requestedTarget}`,
619
+ { outDir: requestedTarget, projectRoot }
620
+ );
621
+ }
622
+
623
+ current = parent;
624
+ }
625
+
626
+ return target;
627
+ }
628
+
629
+ function cleanOutputDirectory(project, outDir) {
630
+ const target = resolveOutputDirectory(project, outDir);
631
+ fs.rmSync(target, { recursive: true, force: true });
632
+ fs.mkdirSync(target, { recursive: true });
633
+ return target;
634
+ }
635
+
636
+ function buildProject(project, options = {}) {
637
+ const driver = providerDriver(project);
638
+ if (options.sourceOnly === true) {
639
+ throw new PulseProjectError(
640
+ 'PULSE_SOURCE_ONLY_REMOVED',
641
+ 'pulse build --source-only was removed. Native builds always emit generated source and provider Wasm together.',
642
+ { provider: project.provider, replacement: 'pulse build' }
643
+ );
644
+ }
645
+ if (options.experimentalNativeSize === true && (project.target || 'native') !== 'native') {
646
+ throw new PulseProjectError(
647
+ 'PULSE_EXPERIMENTAL_NATIVE_SIZE_UNSUPPORTED',
648
+ 'The --experimental-native-size flag is available only for Native compilation.',
649
+ {
650
+ target: project.target || 'native',
651
+ required: Object.freeze({ target: 'native' })
652
+ }
653
+ );
654
+ }
655
+ if (!driver.executable) {
656
+ throw new PulseProjectError(
657
+ 'PULSE_BUILD_PROVIDER_REQUIRED',
658
+ 'pulse build requires a deployment provider in the active .pulse/config.ts profile. Use pulse compile for provider-neutral Wasm.',
659
+ { provider: project.provider, supported: providerIds({ executable: true }), replacement: 'pulse compile' }
660
+ );
661
+ }
662
+ const descriptor = assertImplementedTarget(project, 'build');
663
+
664
+ if ((project.target || 'native') === 'javascript') {
665
+ const javascriptApplication = prepareJavascriptApplication(project, {
666
+ load: false,
667
+ captureLoadError: true,
668
+ allowedPackages: options.allowedPackages
669
+ });
670
+ if (javascriptApplication.plan.loadable !== true) {
671
+ throw new PulseProjectError(
672
+ 'PULSE_JAVASCRIPT_SOURCE_PACKAGE_PLAN_UNAVAILABLE',
673
+ 'pulse build requires a loadable JavaScript application plan.',
674
+ {
675
+ provider: project.provider,
676
+ target: 'javascript',
677
+ blockers: javascriptApplication.plan.blockers,
678
+ automaticFallback: false
679
+ }
680
+ );
681
+ }
682
+ const compiled = compileProject(project);
683
+ const eventSupport = assertEventCommandEligible(project, compiled, 'build', descriptor);
684
+ const targetSupport = selectedTargetSupportEvidence(project, compiled, javascriptApplication, descriptor, options);
685
+ if (targetSupport && targetSupport.project.status !== 'eligible') {
686
+ throw new PulseProjectError(
687
+ 'PULSE_PROVIDER_CAPABILITY_UNSUPPORTED',
688
+ 'pulse build cannot realize one or more project capabilities for the selected JavaScript target.',
689
+ {
690
+ provider: project.provider,
691
+ target: 'javascript',
692
+ status: targetSupport.project.status,
693
+ reasonIds: targetSupport.project.reasonIds,
694
+ targetSupport,
695
+ automaticFallback: false
696
+ }
697
+ );
698
+ }
699
+ const requestedOutDir = options.outDir || project.outDir;
700
+ const outDir = options.clean === false
701
+ ? resolveOutputDirectory(project, requestedOutDir)
702
+ : cleanOutputDirectory(project, requestedOutDir);
703
+ const javascript = driver.javascript;
704
+ if (!javascript || typeof javascript.writeSourcePackage !== 'function') {
705
+ throw new PulseProjectError(
706
+ 'PULSE_TARGET_IMPLEMENTATION_PENDING',
707
+ 'The selected provider does not implement JavaScript source packaging.',
708
+ { provider: project.provider, target: 'javascript', automaticFallback: false }
709
+ );
710
+ }
711
+ const providerPlan = providerLoweringPlan(project, compiled.metadata);
712
+ const invocation = providerTargetInvocation(
713
+ project,
714
+ 'write-javascript',
715
+ javascriptApplication.plan,
716
+ providerPlan,
717
+ {
718
+ outDir,
719
+ javascript: Object.freeze({
720
+ schemaBundle: compiled.schema.bundle,
721
+ reporting: project.reporting,
722
+ strict: project.strict !== false,
723
+ maxStructuredBodyBytes: project.schemas && project.schemas.maxBytes,
724
+ targetSupport
725
+ })
726
+ }
727
+ );
728
+ const sourcePackage = javascript.writeSourcePackage(invocation);
729
+ const sourcePackageDescription = javascript.describeSourcePackage(sourcePackage, {
730
+ outDir,
731
+ plan: javascriptApplication.plan
732
+ });
733
+ const packageInspection = writePackageInspectionArtifacts(compiled, outDir);
734
+ const eventInspection = writeEventInspectionArtifacts(project, compiled, outDir, eventSupport);
735
+ const manifest = Object.freeze({
736
+ version: PROJECT_EXECUTION_VERSION,
737
+ status: 'built',
738
+ buildMode: 'javascript-source-package',
739
+ provider: project.provider,
740
+ configuredTarget: 'javascript',
741
+ automaticFallback: false,
742
+ reporting: project.reportingPolicy,
743
+ cryptoRealizationPlan: compiled.cryptoRealizationPlan,
744
+ targetDescriptor: Object.freeze({ ...descriptor, resolvedReporting: project.reportingPolicy }),
745
+ providerTarget: Object.freeze({
746
+ package: driver.descriptor && driver.descriptor.package,
747
+ target: descriptor.targetId,
748
+ status: descriptor.status,
749
+ deployable: true,
750
+ deploymentCandidate: sourcePackageDescription.deploymentCandidate,
751
+ deploymentValidated: false,
752
+ providerRealityValidated: false,
753
+ sourcePackage: true,
754
+ sourceOnly: true,
755
+ nativeWasm: false,
756
+ compiledWasmPresent: false,
757
+ javascriptRuntime: true,
758
+ jsComputeRuntime: false,
759
+ downstreamJavascriptRuntimeWasm: sourcePackageDescription.downstreamJavascriptRuntimeWasm,
760
+ executionReady: descriptor.requestAdapter === true && descriptor.lifecycle === true,
761
+ applicationLoader: descriptor.applicationLoader === true,
762
+ requestAdapter: descriptor.requestAdapter === true,
763
+ lifecycle: descriptor.lifecycle === true
764
+ }),
765
+ project: Object.freeze({
766
+ root: '.',
767
+ config: project.configFile ? relative(project.configFile, project.root) : undefined,
768
+ entry: relative(project.entryFile, project.root),
769
+ outDir: '.'
770
+ }),
771
+ application: Object.freeze({
772
+ plan: path.basename(sourcePackage.paths.applicationPlan),
773
+ planHash: javascriptApplication.plan.planHash,
774
+ graphHash: javascriptApplication.plan.graph.graphHash,
775
+ loadable: true,
776
+ sourcePackage: path.basename(sourcePackage.paths.manifest),
777
+ entry: sourcePackageDescription.application.entry,
778
+ package: path.basename(sourcePackage.paths.package),
779
+ modules: sourcePackageDescription.application.modules,
780
+ dependencies: sourcePackage.manifest.package.dependencies,
781
+ ...sourcePackageDescription.application
782
+ }),
783
+ schemas: sourcePackage.manifest.schemas,
784
+ packageInspection: packageInspectionManifest(packageInspection),
785
+ ...(eventInspection ? { events: eventManifestProjection(eventInspection) } : {}),
786
+ targetSupport
787
+ });
788
+ const manifestFile = path.join(outDir, BUILD_MANIFEST);
789
+ fs.writeFileSync(manifestFile, stableJson(manifest));
790
+ return Object.freeze({
791
+ status: 'built',
792
+ version: PROJECT_EXECUTION_VERSION,
793
+ buildMode: 'javascript-source-package',
794
+ provider: project.provider,
795
+ configuredTarget: 'javascript',
796
+ automaticFallback: false,
797
+ project: projectJson(project),
798
+ outDir,
799
+ files: Object.freeze({
800
+ entry: sourcePackage.paths.entry,
801
+ package: sourcePackage.paths.package,
802
+ applicationPlan: sourcePackage.paths.applicationPlan,
803
+ schemaRegistry: sourcePackage.paths.schemaRegistry,
804
+ schemaCodecs: sourcePackage.paths.schemaCodecs,
805
+ ...sourcePackageDescription.files,
806
+ sourcePackage: sourcePackage.paths.manifest,
807
+ ...(eventInspection ? {
808
+ eventCatalog: eventInspection.catalogFile,
809
+ eventInspection: eventInspection.inspectionFile
810
+ } : {}),
811
+ manifest: manifestFile
812
+ }),
813
+ targetSupport,
814
+ packageInspection,
815
+ ...(eventInspection ? { events: eventInspection.inspection } : {}),
816
+ sourcePackage: sourcePackage.manifest,
817
+ manifest
818
+ });
819
+ }
820
+
821
+ const prepared = compileNativeProjectInMemory(project, options);
822
+ const eventSupport = assertEventCommandEligible(project, prepared.compiled, 'build', descriptor);
823
+ const requestedOutDir = options.outDir || project.outDir;
824
+ const outDir = options.clean === false
825
+ ? resolveOutputDirectory(project, requestedOutDir)
826
+ : cleanOutputDirectory(project, requestedOutDir);
827
+ fs.mkdirSync(outDir, { recursive: true });
828
+
829
+ const build = writeCanonicalBuild(prepared.compiled, outDir);
830
+ const nativeBuild = writeCanonicalNativeModule(prepared.native, outDir);
831
+ const packageInspection = writePackageInspectionArtifacts(prepared.compiled, outDir);
832
+ const eventInspection = writeEventInspectionArtifacts(project, prepared.compiled, outDir, eventSupport);
833
+ const lowering = providerLoweringPlan(project, prepared.compiled.metadata);
834
+ const providerBuild = driver.writeTarget
835
+ ? normalizeProviderTargetResult(driver.writeTarget(providerTargetInvocation(
836
+ project,
837
+ 'write-native',
838
+ prepared.plan,
839
+ lowering,
840
+ {
841
+ outDir,
842
+ native: prepared.native,
843
+ optimization: prepared.native.manifest.optimization,
844
+ timeoutMs: options.timeoutMs
845
+ }
846
+ )), { action: 'write-native', provider: project.provider, target: 'native' })
847
+ : undefined;
848
+ const providerFiles = providerBuild ? providerBuild.files : Object.freeze({});
849
+ const providerBuildMetadata = providerBuild && providerBuild.build;
850
+ const nativeManifest = prepared.native.manifest;
851
+
852
+ const manifest = Object.freeze({
853
+ version: PROJECT_EXECUTION_VERSION,
854
+ status: 'built',
855
+ buildMode: 'native-provider',
856
+ provider: project.provider,
857
+ configuredTarget: 'native',
858
+ reporting: project.reportingPolicy,
859
+ cryptoRealizationPlan: prepared.compiled.cryptoRealizationPlan,
860
+ targetDescriptor: targetDescriptor(project, 'native'),
861
+ providerTarget: Object.freeze({
862
+ package: driver.descriptor && driver.descriptor.package,
863
+ buildTarget: driver.descriptor && driver.descriptor.buildTarget,
864
+ target: providerBuildMetadata && providerBuildMetadata.target,
865
+ deployable: driver.deployable === true,
866
+ deploymentValidated: driver.deploymentValidated === true,
867
+ sourcePackage: driver.sourcePackage === true,
868
+ sourceOnly: false,
869
+ sourceOnlySupported: false,
870
+ nativeWasm: true,
871
+ providerNeutralInput: true,
872
+ compiledWasmPresent: true,
873
+ javascriptRuntime: false,
874
+ jsComputeRuntime: false,
875
+ compiler: providerBuildMetadata && providerBuildMetadata.compiler,
876
+ optimization: providerBuildMetadata && providerBuildMetadata.optimization,
877
+ wasm: providerBuildMetadata && providerBuildMetadata.wasm,
878
+ wat: providerBuildMetadata && providerBuildMetadata.wat,
879
+ importModules: providerBuildMetadata && providerBuildMetadata.importModules,
880
+ imports: providerBuildMetadata && providerBuildMetadata.imports,
881
+ exports: providerBuildMetadata && providerBuildMetadata.exports,
882
+ localConformanceRuntime: driver.localExecution === true,
883
+ lowering
884
+ }),
885
+ project: Object.freeze({
886
+ root: '.',
887
+ config: project.configFile ? relative(project.configFile, project.root) : undefined,
888
+ entry: relative(project.entryFile, project.root),
889
+ outDir: relative(outDir, project.root)
890
+ }),
891
+ program: Object.freeze({
892
+ file: path.basename(build.programFile),
893
+ handler: path.basename(build.handlerFile),
894
+ sourceHash: prepared.compiled.metadata.sourceHash,
895
+ compilerVersion: prepared.compiled.metadata.compilerVersion,
896
+ runtimeProtocolVersion: prepared.compiled.metadata.runtimeProtocolVersion,
897
+ authoring: prepared.compiled.metadata.authoring,
898
+ application: prepared.compiled.metadata.application,
899
+ routing: prepared.plan.routing,
900
+ json: prepared.compiled.metadata.json,
901
+ warnings: prepared.compiled.metadata.warnings,
902
+ warningCount: prepared.compiled.metadata.warningCount || 0,
903
+ capabilities: prepared.compiled.metadata.capabilities,
904
+ effectCount: prepared.compiled.metadata.effectCount,
905
+ continuationCount: prepared.compiled.metadata.continuationCount,
906
+ groupedContinuationCount: prepared.compiled.metadata.groupedContinuationCount,
907
+ opaqueReturnCount: prepared.compiled.metadata.opaqueReturnCount,
908
+ projectSourceHash: prepared.compiled.metadata.projectSourceHash,
909
+ schemaReferenceCount: prepared.compiled.metadata.schemaReferenceCount,
910
+ schemaSourceHash: prepared.compiled.metadata.schemaSourceHash
911
+ }),
912
+ portable: Object.freeze({
913
+ target: 'portable-native-wasm',
914
+ providerNeutral: true,
915
+ version: prepared.native.version,
916
+ compilerVersion: prepared.native.compilerVersion,
917
+ planVersion: prepared.plan.version,
918
+ planCompilerVersion: prepared.plan.compilerVersion,
919
+ planHash: prepared.plan.planHash,
920
+ ownership: prepared.plan.ownership,
921
+ summary: prepared.plan.summary,
922
+ logging: prepared.plan.logging,
923
+ ...(prepared.plan.json ? { json: prepared.plan.json } : {}),
924
+ ...(prepared.plan.requestState ? { requestState: prepared.plan.requestState } : {}),
925
+ assemblyScript: nativeManifest.assemblyScript,
926
+ optimization: nativeManifest.optimization,
927
+ source: Object.freeze({ file: path.basename(nativeBuild.sourceFile), sha256: prepared.native.sourceHash }),
928
+ wasm: Object.freeze({ file: path.basename(nativeBuild.wasmFile), ...nativeManifest.wasm }),
929
+ wat: Object.freeze({ file: path.basename(nativeBuild.watFile), ...nativeManifest.wat }),
930
+ plan: path.basename(nativeBuild.planFile),
931
+ manifest: path.basename(nativeBuild.manifestFile),
932
+ packageRealizationArtifacts: Object.freeze({
933
+ ...(nativeBuild.realizationArtifactsFile
934
+ ? { file: path.basename(nativeBuild.realizationArtifactsFile) }
935
+ : {}),
936
+ ...nativeManifest.packageRealizationArtifacts
937
+ }),
938
+ ...(nativeBuild.guestUnitPlanFile ? {
939
+ guestUnit: Object.freeze({
940
+ plan: path.basename(nativeBuild.guestUnitPlanFile),
941
+ report: path.basename(nativeBuild.guestLinkReportFile),
942
+ audit: path.basename(nativeBuild.finalWasmAuditFile),
943
+ finalArtifact: nativeManifest.guestLinkReport.finalArtifact,
944
+ providerPackaging: nativeManifest.providerPackaging
945
+ })
946
+ } : {}),
947
+ importModules: nativeManifest.importModules,
948
+ imports: nativeManifest.imports,
949
+ exports: nativeManifest.exports,
950
+ policy: nativeManifest.policy
951
+ }),
952
+ schemas: Object.freeze({
953
+ active: prepared.compiled.schema.active,
954
+ registry: build.schemaRegistryFile ? path.basename(build.schemaRegistryFile) : undefined,
955
+ codecs: build.schemaCodecsFile ? path.basename(build.schemaCodecsFile) : undefined,
956
+ ids: prepared.compiled.metadata.schemaIds,
957
+ references: prepared.compiled.metadata.schemaReferences,
958
+ sourceHash: prepared.compiled.metadata.schemaSourceHash,
959
+ policy: prepared.compiled.metadata.json
960
+ }),
961
+ packageInspection: packageInspectionManifest(packageInspection),
962
+ ...(eventInspection ? { events: eventManifestProjection(eventInspection) } : {})
963
+ });
964
+ const manifestFile = path.join(outDir, BUILD_MANIFEST);
965
+ fs.writeFileSync(manifestFile, stableJson(manifest));
966
+ return Object.freeze({
967
+ status: 'built',
968
+ version: PROJECT_EXECUTION_VERSION,
969
+ buildMode: 'native-provider',
970
+ provider: project.provider,
971
+ project: projectJson(project),
972
+ outDir,
973
+ files: Object.freeze({
974
+ handler: build.handlerFile,
975
+ program: build.programFile,
976
+ schemaRegistry: build.schemaRegistryFile,
977
+ schemaCodecs: build.schemaCodecsFile,
978
+ nativeSource: nativeBuild.sourceFile,
979
+ nativeWasm: nativeBuild.wasmFile,
980
+ nativeWat: nativeBuild.watFile,
981
+ nativePlan: nativeBuild.planFile,
982
+ nativeManifest: nativeBuild.manifestFile,
983
+ nativePackageArtifacts: nativeBuild.realizationArtifactsFile,
984
+ guestUnitPlan: nativeBuild.guestUnitPlanFile,
985
+ guestLinkReport: nativeBuild.guestLinkReportFile,
986
+ finalWasmAudit: nativeBuild.finalWasmAuditFile,
987
+ ...(eventInspection ? {
988
+ eventCatalog: eventInspection.catalogFile,
989
+ eventInspection: eventInspection.inspectionFile
990
+ } : {}),
991
+ manifest: manifestFile,
992
+ ...providerFiles
993
+ }),
994
+ metadata: prepared.compiled.metadata,
995
+ packageInspection,
996
+ ...(eventInspection ? { events: eventInspection.inspection } : {}),
997
+ native: Object.freeze({
998
+ version: prepared.native.version,
999
+ compilerVersion: prepared.native.compilerVersion,
1000
+ planVersion: prepared.plan.version,
1001
+ planHash: prepared.plan.planHash,
1002
+ summary: prepared.plan.summary,
1003
+ logging: prepared.plan.logging,
1004
+ ...(prepared.plan.json ? { json: prepared.plan.json } : {}),
1005
+ ...(prepared.plan.requestState ? { requestState: prepared.plan.requestState } : {}),
1006
+ assemblyScript: nativeManifest.assemblyScript,
1007
+ optimization: nativeManifest.optimization,
1008
+ wasm: nativeManifest.wasm,
1009
+ importModules: nativeManifest.importModules,
1010
+ exports: nativeManifest.exports
1011
+ }),
1012
+ manifest
1013
+ });
1014
+ }
1015
+
1016
+ function compileNativeProject(project, options = {}) {
1017
+ const requestedOutDir = options.outDir || project.outDir;
1018
+ const outDir = options.clean === false
1019
+ ? resolveOutputDirectory(project, requestedOutDir)
1020
+ : cleanOutputDirectory(project, requestedOutDir);
1021
+ fs.mkdirSync(outDir, { recursive: true });
1022
+
1023
+ const prepared = compileNativeProjectInMemory(project, options);
1024
+ const javascriptApplication = (project.target || 'native') === 'javascript'
1025
+ ? prepareJavascriptApplication(project, { load: false, captureLoadError: true, allowedPackages: options.allowedPackages })
1026
+ : null;
1027
+ const targetSupport = javascriptApplication
1028
+ ? selectedTargetSupportEvidence(project, prepared.compiled, javascriptApplication, javascriptApplication.descriptor, options)
1029
+ : null;
1030
+ const eventSupport = selectedEventTargetSupport(project, prepared.compiled);
1031
+ const build = writeCanonicalBuild(prepared.compiled, outDir);
1032
+ const nativeBuild = writeCanonicalNativeModule(prepared.native, outDir);
1033
+ const packageInspection = writePackageInspectionArtifacts(prepared.compiled, outDir);
1034
+ const eventInspection = writeEventInspectionArtifacts(project, prepared.compiled, outDir, eventSupport);
1035
+ const nativeManifest = prepared.native.manifest;
1036
+ const manifest = Object.freeze({
1037
+ version: PROJECT_EXECUTION_VERSION,
1038
+ status: 'compiled',
1039
+ target: 'portable-native-wasm',
1040
+ provider: null,
1041
+ providerNeutral: true,
1042
+ configuredProvider: project.provider,
1043
+ configuredTarget: project.target || 'native',
1044
+ automaticFallback: false,
1045
+ reporting: project.reportingPolicy,
1046
+ cryptoRealizationPlan: prepared.compiled.cryptoRealizationPlan,
1047
+ ...(targetSupport ? { targetSupport } : {}),
1048
+ project: Object.freeze({
1049
+ root: '.',
1050
+ config: project.configFile ? relative(project.configFile, project.root) : undefined,
1051
+ entry: relative(project.entryFile, project.root),
1052
+ outDir: relative(outDir, project.root)
1053
+ }),
1054
+ program: Object.freeze({
1055
+ file: path.basename(build.programFile),
1056
+ handler: path.basename(build.handlerFile),
1057
+ sourceHash: prepared.compiled.metadata.sourceHash,
1058
+ compilerVersion: prepared.compiled.metadata.compilerVersion,
1059
+ runtimeProtocolVersion: prepared.compiled.metadata.runtimeProtocolVersion,
1060
+ authoring: prepared.compiled.metadata.authoring,
1061
+ application: prepared.compiled.metadata.application,
1062
+ routing: prepared.plan.routing,
1063
+ json: prepared.compiled.metadata.json,
1064
+ warnings: prepared.compiled.metadata.warnings,
1065
+ warningCount: prepared.compiled.metadata.warningCount || 0,
1066
+ capabilities: prepared.compiled.metadata.capabilities,
1067
+ effectCount: prepared.compiled.metadata.effectCount,
1068
+ continuationCount: prepared.compiled.metadata.continuationCount,
1069
+ groupedContinuationCount: prepared.compiled.metadata.groupedContinuationCount,
1070
+ opaqueReturnCount: prepared.compiled.metadata.opaqueReturnCount,
1071
+ projectSourceHash: prepared.compiled.metadata.projectSourceHash,
1072
+ schemaReferenceCount: prepared.compiled.metadata.schemaReferenceCount,
1073
+ schemaSourceHash: prepared.compiled.metadata.schemaSourceHash
1074
+ }),
1075
+ native: Object.freeze({
1076
+ version: prepared.native.version,
1077
+ compilerVersion: prepared.native.compilerVersion,
1078
+ planVersion: prepared.plan.version,
1079
+ planCompilerVersion: prepared.plan.compilerVersion,
1080
+ planHash: prepared.plan.planHash,
1081
+ ownership: prepared.plan.ownership,
1082
+ summary: prepared.plan.summary,
1083
+ logging: prepared.plan.logging,
1084
+ ...(prepared.plan.json ? { json: prepared.plan.json } : {}),
1085
+ ...(prepared.plan.requestState ? { requestState: prepared.plan.requestState } : {}),
1086
+ assemblyScript: nativeManifest.assemblyScript,
1087
+ optimization: nativeManifest.optimization,
1088
+ source: Object.freeze({
1089
+ file: path.basename(nativeBuild.sourceFile),
1090
+ sha256: prepared.native.sourceHash
1091
+ }),
1092
+ wasm: Object.freeze({
1093
+ file: path.basename(nativeBuild.wasmFile),
1094
+ ...nativeManifest.wasm
1095
+ }),
1096
+ wat: Object.freeze({
1097
+ file: path.basename(nativeBuild.watFile),
1098
+ ...nativeManifest.wat
1099
+ }),
1100
+ plan: path.basename(nativeBuild.planFile),
1101
+ manifest: path.basename(nativeBuild.manifestFile),
1102
+ packageRealizationArtifacts: Object.freeze({
1103
+ ...(nativeBuild.realizationArtifactsFile
1104
+ ? { file: path.basename(nativeBuild.realizationArtifactsFile) }
1105
+ : {}),
1106
+ ...nativeManifest.packageRealizationArtifacts
1107
+ }),
1108
+ ...(nativeBuild.guestUnitPlanFile ? {
1109
+ guestUnit: Object.freeze({
1110
+ plan: path.basename(nativeBuild.guestUnitPlanFile),
1111
+ report: path.basename(nativeBuild.guestLinkReportFile),
1112
+ audit: path.basename(nativeBuild.finalWasmAuditFile),
1113
+ finalArtifact: nativeManifest.guestLinkReport.finalArtifact,
1114
+ providerPackaging: nativeManifest.providerPackaging
1115
+ })
1116
+ } : {}),
1117
+ importModules: nativeManifest.importModules,
1118
+ imports: nativeManifest.imports,
1119
+ exports: nativeManifest.exports,
1120
+ policy: nativeManifest.policy
1121
+ }),
1122
+ schemas: Object.freeze({
1123
+ active: prepared.compiled.schema.active,
1124
+ registry: build.schemaRegistryFile ? path.basename(build.schemaRegistryFile) : undefined,
1125
+ codecs: build.schemaCodecsFile ? path.basename(build.schemaCodecsFile) : undefined,
1126
+ ids: prepared.compiled.metadata.schemaIds,
1127
+ references: prepared.compiled.metadata.schemaReferences,
1128
+ sourceHash: prepared.compiled.metadata.schemaSourceHash,
1129
+ policy: prepared.compiled.metadata.json
1130
+ }),
1131
+ packageInspection: packageInspectionManifest(packageInspection),
1132
+ ...(eventInspection ? { events: eventManifestProjection(eventInspection) } : {})
1133
+ });
1134
+ const manifestFile = path.join(outDir, COMPILE_MANIFEST);
1135
+ fs.writeFileSync(manifestFile, stableJson(manifest));
1136
+
1137
+ return Object.freeze({
1138
+ status: 'compiled',
1139
+ version: PROJECT_EXECUTION_VERSION,
1140
+ target: 'portable-native-wasm',
1141
+ provider: null,
1142
+ providerNeutral: true,
1143
+ configuredProvider: project.provider,
1144
+ configuredTarget: project.target || 'native',
1145
+ automaticFallback: false,
1146
+ targetSupport,
1147
+ project: projectJson(project),
1148
+ outDir,
1149
+ files: Object.freeze({
1150
+ handler: build.handlerFile,
1151
+ program: build.programFile,
1152
+ schemaRegistry: build.schemaRegistryFile,
1153
+ schemaCodecs: build.schemaCodecsFile,
1154
+ nativeSource: nativeBuild.sourceFile,
1155
+ nativeWasm: nativeBuild.wasmFile,
1156
+ nativeWat: nativeBuild.watFile,
1157
+ nativePlan: nativeBuild.planFile,
1158
+ nativeManifest: nativeBuild.manifestFile,
1159
+ nativePackageArtifacts: nativeBuild.realizationArtifactsFile,
1160
+ guestUnitPlan: nativeBuild.guestUnitPlanFile,
1161
+ guestLinkReport: nativeBuild.guestLinkReportFile,
1162
+ finalWasmAudit: nativeBuild.finalWasmAuditFile,
1163
+ ...(eventInspection ? {
1164
+ eventCatalog: eventInspection.catalogFile,
1165
+ eventInspection: eventInspection.inspectionFile
1166
+ } : {}),
1167
+ manifest: manifestFile
1168
+ }),
1169
+ metadata: prepared.compiled.metadata,
1170
+ packageInspection,
1171
+ ...(eventInspection ? { events: eventInspection.inspection } : {}),
1172
+ native: Object.freeze({
1173
+ version: prepared.native.version,
1174
+ compilerVersion: prepared.native.compilerVersion,
1175
+ planVersion: prepared.plan.version,
1176
+ planHash: prepared.plan.planHash,
1177
+ summary: prepared.plan.summary,
1178
+ logging: prepared.plan.logging,
1179
+ ...(prepared.plan.json ? { json: prepared.plan.json } : {}),
1180
+ ...(prepared.plan.requestState ? { requestState: prepared.plan.requestState } : {}),
1181
+ assemblyScript: nativeManifest.assemblyScript,
1182
+ optimization: nativeManifest.optimization,
1183
+ wasm: nativeManifest.wasm,
1184
+ importModules: nativeManifest.importModules,
1185
+ exports: nativeManifest.exports
1186
+ }),
1187
+ manifest
1188
+ });
1189
+ }
1190
+
1191
+ function headerValue(headers, name) {
1192
+ const lower = String(name).toLowerCase();
1193
+ const values = (headers || []).filter(([key]) => String(key).toLowerCase() === lower).map(([, value]) => String(value));
1194
+ return values.length <= 1 ? values[0] : values;
1195
+ }
1196
+
1197
+ function responseJson(response) {
1198
+ if (response.bodyClass === 'opaque') throw new Error('Opaque response cannot be decoded as JSON.');
1199
+ return JSON.parse(response.body || 'null');
1200
+ }
1201
+
1202
+ function statusAllowsResponseBody(status) {
1203
+ const value = Number(status);
1204
+ return value !== 204 && value !== 205 && value !== 304 && !(value >= 100 && value < 200);
1205
+ }
1206
+
1207
+ function observableTestResponse(testCase, response) {
1208
+ const method = String(testCase.request && testCase.request.method || 'GET').toUpperCase();
1209
+ if (method !== 'HEAD' && statusAllowsResponseBody(response.status)) return response;
1210
+ return Object.freeze({ ...response, body: '' });
1211
+ }
1212
+
1213
+ function materializeTestResponse(response) {
1214
+ if (!response || response.bodyClass !== 'opaque' || response.body !== undefined) return response;
1215
+ const chunks = response.bodyStream && Array.isArray(response.bodyStream.chunks)
1216
+ ? response.bodyStream.chunks
1217
+ : undefined;
1218
+ if (!chunks) return response;
1219
+ const body = Buffer.concat(chunks.map((chunk) => Buffer.isBuffer(chunk)
1220
+ ? chunk
1221
+ : chunk instanceof Uint8Array
1222
+ ? Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength)
1223
+ : Buffer.from(String(chunk)))).toString('utf8');
1224
+ return Object.freeze({ ...response, body });
1225
+ }
1226
+
1227
+ function assertExpectation(testCase, execution) {
1228
+ const expected = testCase.expect;
1229
+ const response = observableTestResponse(testCase, execution.response);
1230
+ if (expected.status !== undefined) assert.equal(response.status, expected.status, `${testCase.name}: unexpected status`);
1231
+ if (expected.bodyClass !== undefined) assert.equal(response.bodyClass, expected.bodyClass, `${testCase.name}: unexpected body class`);
1232
+ if (Object.prototype.hasOwnProperty.call(expected, 'json') && expected.json !== undefined) assert.deepEqual(responseJson(response), expected.json, `${testCase.name}: unexpected JSON body`);
1233
+ if (expected.text !== undefined) assert.equal(String(response.body || ''), expected.text, `${testCase.name}: unexpected text body`);
1234
+ if (expected.headers) {
1235
+ for (const [name, value] of expected.headers) assert.deepEqual(headerValue(response.headers, name), value, `${testCase.name}: unexpected header ${name}`);
1236
+ }
1237
+ }
1238
+
1239
+ function secretTokens(secrets) {
1240
+ return [...new Set(Object.values(secrets || {})
1241
+ .filter((value) => typeof value === 'string' && value.length > 0))]
1242
+ .sort((left, right) => right.length - left.length);
1243
+ }
1244
+
1245
+ function redactString(value, tokens) {
1246
+ let text = String(value);
1247
+ for (const token of tokens) text = text.split(token).join('<redacted>');
1248
+ return text;
1249
+ }
1250
+
1251
+ function redactValue(value, tokens, seen = new WeakSet()) {
1252
+ if (typeof value === 'string') return redactString(value, tokens);
1253
+ if (value === null || value === undefined || typeof value !== 'object') return value;
1254
+ if (Buffer.isBuffer(value)) return '<binary>';
1255
+ if (seen.has(value)) return '<circular>';
1256
+ seen.add(value);
1257
+ if (Array.isArray(value)) return value.map((entry) => redactValue(entry, tokens, seen));
1258
+ const out = {};
1259
+ for (const [key, entry] of Object.entries(value)) out[key] = redactValue(entry, tokens, seen);
1260
+ return out;
1261
+ }
1262
+
1263
+ function errorSummary(error, secrets) {
1264
+ const tokens = secretTokens(secrets);
1265
+ const code = error && error.code ? String(error.code) : undefined;
1266
+ const descriptor = describeDiagnostic(code);
1267
+ const diagnostics = error && Array.isArray(error.diagnostics)
1268
+ ? Object.freeze(redactValue(error.diagnostics, tokens).map((entry) => decorateDiagnostic(entry)))
1269
+ : undefined;
1270
+ return Object.freeze({
1271
+ name: error && error.name ? String(error.name) : 'Error',
1272
+ code,
1273
+ title: descriptor.title,
1274
+ summary: descriptor.summary,
1275
+ category: descriptor.category,
1276
+ message: redactString(error && error.message ? error.message : String(error), tokens),
1277
+ remediation: descriptor.remediation,
1278
+ stability: descriptor.stability,
1279
+ scope: descriptor.scope,
1280
+ docs: descriptor.docs,
1281
+ detail: error && error.detail ? Object.freeze(redactValue(error.detail, tokens)) : undefined,
1282
+ diagnostics,
1283
+ execution: error && error.execution ? Object.freeze(redactValue({
1284
+ executionId: error.execution.executionId,
1285
+ resolutionOrder: error.execution.resolutionOrder,
1286
+ continuations: error.execution.continuations
1287
+ }, tokens)) : undefined
1288
+ });
1289
+ }
1290
+
1291
+ function assertExpectedError(testCase, error) {
1292
+ const expected = testCase.expect.error;
1293
+ if (!expected) throw error;
1294
+ if (expected.name !== undefined) assert.equal(error.name, expected.name, `${testCase.name}: unexpected error name`);
1295
+ if (expected.code !== undefined) assert.equal(error.code, expected.code, `${testCase.name}: unexpected error code`);
1296
+ if (expected.category !== undefined) assert.equal(error.category, expected.category, `${testCase.name}: unexpected error category`);
1297
+ if (expected.message !== undefined) assert.match(String(error.message || ''), new RegExp(String(expected.message)), `${testCase.name}: unexpected error message`);
1298
+ }
1299
+
1300
+ function assertEventExpectation(testCase, execution) {
1301
+ const expected = testCase.expect;
1302
+ const result = eventContracts.normalizeEventExecutionResult(execution.result);
1303
+ assert.equal(result.status, expected.status, `${testCase.name}: unexpected event execution status`);
1304
+ if (expected.error) {
1305
+ assert.ok(result.error, `${testCase.name}: expected an event execution error`);
1306
+ if (expected.error.name !== undefined) assert.equal(result.error.name, expected.error.name, `${testCase.name}: unexpected event error name`);
1307
+ if (expected.error.code !== undefined) assert.equal(result.error.code, expected.error.code, `${testCase.name}: unexpected event error code`);
1308
+ if (expected.error.category !== undefined) assert.equal(result.error.category, expected.error.category, `${testCase.name}: unexpected event error category`);
1309
+ if (expected.error.message !== undefined) assert.match(String(result.error.message || ''), new RegExp(String(expected.error.message)), `${testCase.name}: unexpected event error message`);
1310
+ }
1311
+ assert.deepEqual(execution.emittedFrames, expected.emitted, `${testCase.name}: unexpected emitted event frames`);
1312
+ return result;
1313
+ }
1314
+
1315
+ async function executeProviderEventTestCase(driver, target, application, testCase, options = {}) {
1316
+ if (!driver.events || !driver.events.targets.includes(target) || typeof driver.events.executeTestCase !== 'function') {
1317
+ throw new PulseProjectError(
1318
+ 'PULSE_EVENT_TARGET_UNSUPPORTED',
1319
+ `The selected ${driver.id}/${target} provider target does not implement event test execution.`,
1320
+ { provider: driver.id, target, command: 'test', automaticFallback: false }
1321
+ );
1322
+ }
1323
+ return driver.events.executeTestCase(Object.freeze({
1324
+ target,
1325
+ application,
1326
+ testCase,
1327
+ options: Object.freeze({ ...options })
1328
+ }));
1329
+ }
1330
+
1331
+ function eventTestCaseResult(testCase, execution, result, started) {
1332
+ const evidence = execution.executionEvidence || {};
1333
+ const effectCount = Number(evidence.effectCount === undefined ? evidence.ownedEffectCount || 0 : evidence.effectCount);
1334
+ return Object.freeze({
1335
+ name: testCase.name,
1336
+ kind: 'event',
1337
+ status: 'passed',
1338
+ durationMs: Number(process.hrtime.bigint() - started) / 1e6,
1339
+ event: Object.freeze({ type: testCase.event.type, schemaId: testCase.event.schemaId }),
1340
+ result,
1341
+ emittedFrames: Object.freeze(redactValue(execution.emittedFrames, secretTokens(testCase.secrets))),
1342
+ emittedFrameCount: execution.emittedFrames.length,
1343
+ effects: effectCount,
1344
+ adapter: execution.adapter
1345
+ });
1346
+ }
1347
+
1348
+ async function runJavascriptProjectTests(project, options = {}) {
1349
+ const descriptor = assertImplementedTarget(project, 'test');
1350
+ const javascript = providerDriver(project).javascript;
1351
+ if (!javascript || typeof javascript.executeTestCase !== 'function' || descriptor.applicationLoader !== true || descriptor.requestAdapter !== true) {
1352
+ throw new PulseProjectError(
1353
+ 'PULSE_TARGET_IMPLEMENTATION_PENDING',
1354
+ `pulse test cannot realize the selected javascript target for ${project.provider} yet.`,
1355
+ { target: 'javascript', command: 'test', provider: project.provider, targetDescriptor: descriptor, automaticFallback: false }
1356
+ );
1357
+ }
1358
+ const selected = options.caseName ? project.tests.filter((entry) => entry.name === options.caseName) : project.tests;
1359
+ if (selected.length === 0) {
1360
+ throw new PulseProjectError('PULSE_TEST_CASES_MISSING', options.caseName ? `No Pulse test case named ${options.caseName}.` : 'Pulse project defines no test cases.', { available: project.tests.map((entry) => entry.name) });
1361
+ }
1362
+ const localEmulation = javascript.localEmulation === true;
1363
+ const compiled = compileProject(project);
1364
+ const eventSupport = selectedEventTargetSupport(project, compiled, descriptor);
1365
+ if (eventSupport) assertEventCommandEligible(project, compiled, 'test', descriptor);
1366
+ if (selected.some((testCase) => testCase.kind === 'event') && !eventSupport) {
1367
+ throw new PulseProjectError('PULSE_TEST_EVENT_INVALID', 'The test harness contains an event case, but the application has no reachable event topology.');
1368
+ }
1369
+ const prepared = prepareJavascriptApplication(project, {
1370
+ allowedPackages: options.allowedPackages,
1371
+ localEmulation,
1372
+ schemaBundle: compiled.schema.bundle
1373
+ });
1374
+ if (!prepared.loaded) {
1375
+ throw new PulseProjectError('PULSE_JAVASCRIPT_APPLICATION_UNAVAILABLE', 'The graph-backed JavaScript application could not be loaded for project tests.', {
1376
+ planHash: prepared.plan.planHash,
1377
+ blockers: prepared.plan.blockers,
1378
+ automaticFallback: false
1379
+ });
1380
+ }
1381
+ const schemaCodecs = createCanonicalSchemaCodecs(compiled.schema.bundle.registry);
1382
+ const cases = [];
1383
+ let failed = 0;
1384
+ for (const testCase of selected) {
1385
+ const started = process.hrtime.bigint();
1386
+ const jsonTrace = [];
1387
+ try {
1388
+ if (testCase.kind === 'event') {
1389
+ const execution = await executeProviderEventTestCase(providerDriver(project), 'javascript', prepared.loaded.application, testCase, {
1390
+ application: Object.freeze({
1391
+ projectHash: project.projectHash,
1392
+ planHash: project.planHash,
1393
+ profile: project.profile,
1394
+ target: 'javascript',
1395
+ provider: project.provider
1396
+ }),
1397
+ schemaCodecs,
1398
+ reporting: project.reporting,
1399
+ networkFetch: project.dev.networkFetch
1400
+ });
1401
+ const result = assertEventExpectation(testCase, execution);
1402
+ cases.push(eventTestCaseResult(testCase, execution, result, started));
1403
+ continue;
1404
+ }
1405
+ const runtimeOptions = {
1406
+ application: Object.freeze({
1407
+ projectHash: project.projectHash,
1408
+ planHash: project.planHash,
1409
+ profile: project.profile,
1410
+ target: 'javascript',
1411
+ provider: project.provider
1412
+ }),
1413
+ maxBodyBytes: testCase.maxBodyBytes === undefined
1414
+ ? (project.schemas.active ? project.schemas.maxBytes : undefined)
1415
+ : testCase.maxBodyBytes,
1416
+ schemaCodecs,
1417
+ strict: project.strict !== false,
1418
+ provider: project.provider,
1419
+ reporting: project.reporting,
1420
+ grip: testCase.grip,
1421
+ onJsonTrace(event) { jsonTrace.push(event); }
1422
+ };
1423
+ const execution = await javascript.executeTestCase(prepared.loaded.application, testCase, {
1424
+ ...runtimeOptions,
1425
+ bindings: project.providerConfig.bindings,
1426
+ networkFetch: project.dev.networkFetch
1427
+ });
1428
+ if (testCase.expect.error) throw new assert.AssertionError({ message: `${testCase.name}: expected ${testCase.expect.error.name || 'an error'} but execution completed` });
1429
+ assertExpectation(testCase, Object.freeze({
1430
+ ...execution,
1431
+ response: materializeTestResponse(execution.response)
1432
+ }));
1433
+ cases.push(Object.freeze({
1434
+ name: testCase.name,
1435
+ status: 'passed',
1436
+ durationMs: Number(process.hrtime.bigint() - started) / 1e6,
1437
+ response: Object.freeze({ status: execution.response.status, bodyClass: execution.response.bodyClass, kind: execution.response.kind }),
1438
+ effects: execution.effectCount,
1439
+ ...(localEmulation ? { providerExecution: execution.provider } : {}),
1440
+ jsonTrace: Object.freeze(jsonTrace),
1441
+ continuations: execution.continuations,
1442
+ resolutionOrder: execution.resolutionOrder
1443
+ }));
1444
+ } catch (error) {
1445
+ try {
1446
+ if (testCase.kind === 'event') throw error;
1447
+ assertExpectedError(testCase, error);
1448
+ cases.push(Object.freeze({ name: testCase.name, status: 'passed', expectedError: errorSummary(error, testCase.secrets), durationMs: Number(process.hrtime.bigint() - started) / 1e6 }));
1449
+ } catch (assertion) {
1450
+ failed += 1;
1451
+ cases.push(Object.freeze({ name: testCase.name, status: 'failed', error: errorSummary(assertion === error ? error : assertion, testCase.secrets), actualError: assertion === error ? undefined : errorSummary(error, testCase.secrets), durationMs: Number(process.hrtime.bigint() - started) / 1e6 }));
1452
+ }
1453
+ }
1454
+ }
1455
+ return Object.freeze({
1456
+ status: failed === 0 ? 'passed' : 'failed',
1457
+ version: PROJECT_EXECUTION_VERSION,
1458
+ provider: project.provider,
1459
+ target: 'javascript',
1460
+ targetId: descriptor.targetId,
1461
+ automaticFallback: false,
1462
+ project: projectJson(project),
1463
+ applicationPlan: Object.freeze({
1464
+ version: prepared.plan.version,
1465
+ planHash: prepared.plan.planHash,
1466
+ graphHash: prepared.plan.graph.graphHash,
1467
+ nativeEligibility: prepared.plan.nativeEligibility,
1468
+ automaticFallback: false
1469
+ }),
1470
+ metadata: Object.freeze({
1471
+ runtimeClass: descriptor.runtimeClass,
1472
+ sourceApplication: true,
1473
+ schemaRegistryHash: compiled.metadata.schemaRegistryHash,
1474
+ schemaCodecTableHash: compiled.metadata.schemaCodecTableHash,
1475
+ schemaIds: compiled.metadata.schemaIds,
1476
+ responseCaseIds: compiled.metadata.responseCaseIds,
1477
+ ...(localEmulation ? {
1478
+ localExecution: Object.freeze({
1479
+ mode: javascript.localExecutionMode,
1480
+ providerReality: false,
1481
+ realityRunner: javascript.realityRunner,
1482
+ automaticFallback: false,
1483
+ loader: Object.freeze({
1484
+ version: prepared.loaded.version,
1485
+ kind: 'provider-owned-bundled-closure',
1486
+ sourceHash: prepared.loaded.closure.sourceHash,
1487
+ bundledInputs: prepared.loaded.closure.inputs.length,
1488
+ packagesLoaded: prepared.loaded.packagesLoaded
1489
+ })
1490
+ })
1491
+ } : {})
1492
+ }),
1493
+ summary: Object.freeze({ total: cases.length, passed: cases.length - failed, failed }),
1494
+ cases: Object.freeze(cases)
1495
+ });
1496
+ }
1497
+
1498
+ async function runProjectTests(project, options = {}) {
1499
+ if ((project.target || 'native') === 'javascript') return runJavascriptProjectTests(project, options);
1500
+ const selected = options.caseName ? project.tests.filter((entry) => entry.name === options.caseName) : project.tests;
1501
+ if (selected.length === 0) {
1502
+ throw new PulseProjectError('PULSE_TEST_CASES_MISSING', options.caseName ? `No Pulse test case named ${options.caseName}.` : 'Pulse project defines no test cases.', { available: project.tests.map((entry) => entry.name) });
1503
+ }
1504
+ const hasEventCase = selected.some((testCase) => testCase.kind === 'event');
1505
+ const descriptor = targetDescriptor(project, 'native');
1506
+ let compiled = hasEventCase ? compileProject(project) : null;
1507
+ const eventSupport = hasEventCase ? selectedEventTargetSupport(project, compiled, descriptor) : null;
1508
+ if (hasEventCase && eventSupport) assertEventCommandEligible(project, compiled, 'test', descriptor);
1509
+ if (hasEventCase && !eventSupport) {
1510
+ throw new PulseProjectError('PULSE_TEST_EVENT_INVALID', 'The test harness contains an event case, but the application has no reachable event topology.');
1511
+ }
1512
+ const driver = assertExecutableProvider(project, 'test');
1513
+ assertImplementedTarget(project, 'test');
1514
+ const executeCanonicalProgram = driver.execute;
1515
+ if (!compiled) compiled = compileProject(project);
1516
+ const exactNativeCrypto = requiresExactNativeCrypto(compiled);
1517
+ const program = exactNativeCrypto ? null : loadCanonicalModule(compiled);
1518
+ const native = hasEventCase || exactNativeCrypto
1519
+ ? compileNativeProjectInMemory(project, { ...options, compiled }).native
1520
+ : null;
1521
+ const cases = [];
1522
+ let failed = 0;
1523
+ for (const testCase of selected) {
1524
+ const started = process.hrtime.bigint();
1525
+ try {
1526
+ if (testCase.kind === 'event') {
1527
+ const schemaCodecs = createCanonicalSchemaCodecs(compiled.schema.bundle.registry);
1528
+ const execution = await executeProviderEventTestCase(driver, 'native', native, testCase, {
1529
+ application: Object.freeze({
1530
+ projectHash: project.projectHash,
1531
+ planHash: project.planHash,
1532
+ profile: project.profile,
1533
+ target: 'native',
1534
+ provider: project.provider
1535
+ }),
1536
+ schemaCodecs,
1537
+ reporting: project.reporting,
1538
+ networkFetch: project.dev.networkFetch
1539
+ });
1540
+ const result = assertEventExpectation(testCase, execution);
1541
+ cases.push(eventTestCaseResult(testCase, execution, result, started));
1542
+ continue;
1543
+ }
1544
+ const executionOptions = providerExecutionOptions(project, {
1545
+ packageArtifacts: packageRealizationArtifactsForCompiled(compiled),
1546
+ request: testCase.request,
1547
+ fetches: testCase.fetches,
1548
+ config: testCase.config,
1549
+ secrets: testCase.secrets,
1550
+ kv: testCase.kv,
1551
+ grip: testCase.grip,
1552
+ maxBodyBytes: testCase.maxBodyBytes === undefined
1553
+ ? (project.schemas.active ? project.schemas.maxBytes : undefined)
1554
+ : testCase.maxBodyBytes,
1555
+ continuationTtlMs: testCase.continuationTtlMs,
1556
+ executionId: `test:${testCase.name}`
1557
+ });
1558
+ const execution = exactNativeCrypto
1559
+ ? await executeCanonicalNativeModule(native, executionOptions)
1560
+ : await executeCanonicalProgram(program, executionOptions);
1561
+ if (testCase.expect.error) throw new assert.AssertionError({ message: `${testCase.name}: expected ${testCase.expect.error.name || 'an error'} but execution completed` });
1562
+ assertExpectation(testCase, Object.freeze({
1563
+ ...execution,
1564
+ response: materializeTestResponse(execution.response)
1565
+ }));
1566
+ cases.push(Object.freeze({
1567
+ name: testCase.name,
1568
+ status: 'passed',
1569
+ durationMs: Number(process.hrtime.bigint() - started) / 1e6,
1570
+ response: Object.freeze({ status: execution.response.status, bodyClass: execution.response.bodyClass, kind: execution.response.kind }),
1571
+ effects: execution.effectCount,
1572
+ continuations: execution.continuations.map((entry) => Object.freeze({ id: entry.id, state: entry.state, effectIds: entry.effectIds })),
1573
+ resolutionOrder: execution.resolutionOrder
1574
+ }));
1575
+ } catch (error) {
1576
+ try {
1577
+ if (testCase.kind === 'event') throw error;
1578
+ assertExpectedError(testCase, error);
1579
+ cases.push(Object.freeze({ name: testCase.name, status: 'passed', expectedError: errorSummary(error, testCase.secrets), durationMs: Number(process.hrtime.bigint() - started) / 1e6 }));
1580
+ } catch (assertion) {
1581
+ failed += 1;
1582
+ cases.push(Object.freeze({ name: testCase.name, status: 'failed', error: errorSummary(assertion === error ? error : assertion, testCase.secrets), actualError: assertion === error ? undefined : errorSummary(error, testCase.secrets), durationMs: Number(process.hrtime.bigint() - started) / 1e6 }));
1583
+ }
1584
+ }
1585
+ }
1586
+ return Object.freeze({
1587
+ status: failed === 0 ? 'passed' : 'failed',
1588
+ version: PROJECT_EXECUTION_VERSION,
1589
+ provider: project.provider,
1590
+ project: projectJson(project),
1591
+ metadata: compiled.metadata,
1592
+ summary: Object.freeze({ total: cases.length, passed: cases.length - failed, failed }),
1593
+ cases: Object.freeze(cases)
1594
+ });
1595
+ }
1596
+
1597
+ function inspectProject(project, options = {}) {
1598
+ const compiled = compileProject(project);
1599
+ const selectedTarget = project.target || 'native';
1600
+ let nativePlan = null;
1601
+ let native = null;
1602
+ let nativeInspectionError = null;
1603
+ try {
1604
+ const prepared = compileNativeProjectInMemory(project, { ...options, compiled });
1605
+ nativePlan = prepared.plan;
1606
+ native = prepared.native;
1607
+ } catch (error) {
1608
+ if (selectedTarget !== 'javascript' && !compiled.packageApplication) throw error;
1609
+ nativeInspectionError = errorSummary(error, project.dev && project.dev.secrets);
1610
+ }
1611
+ const driver = providerDriver(project);
1612
+ const availability = providerTargetAvailability(driver);
1613
+ const selectedDescriptor = targetDescriptor(project);
1614
+ const eventSupport = selectedEventTargetSupport(project, compiled, selectedDescriptor);
1615
+ const eventInspection = eventInspectionProjection(project, compiled, eventSupport);
1616
+ const javascriptApplication = selectedTarget === 'javascript'
1617
+ ? prepareJavascriptApplication(project, { captureLoadError: true })
1618
+ : null;
1619
+ const targetSupport = javascriptApplication
1620
+ ? selectedTargetSupportEvidence(project, compiled, javascriptApplication, selectedDescriptor, options)
1621
+ : null;
1622
+ const effectiveAvailability = targetSupport && options.targetSupportDeclaration
1623
+ ? Object.freeze({ ...availability, javascript: targetSupport.availability.generalAvailable })
1624
+ : availability;
1625
+ const referencedSchemaIds = new Set(compiled.metadata.schemaReferences.map((entry) => entry.id));
1626
+ for (const schemaId of eventInspection && eventInspection.schemas.all || []) referencedSchemaIds.add(schemaId);
1627
+ const realization = selectedTarget === 'native'
1628
+ ? (nativePlan && native && driver.inspectRealization && (!eventSupport || eventSupport.status !== 'blocked')
1629
+ ? normalizeProviderTargetResult(driver.inspectRealization(providerTargetInvocation(
1630
+ project,
1631
+ 'inspect-native',
1632
+ nativePlan,
1633
+ providerLoweringPlan(project, compiled.metadata),
1634
+ {
1635
+ native,
1636
+ optimization: native && native.manifest && native.manifest.optimization,
1637
+ timeoutMs: options.timeoutMs
1638
+ }
1639
+ )), { action: 'inspect-native', provider: project.provider, target: 'native' }).realization
1640
+ : Object.freeze({
1641
+ target: selectedDescriptor.targetId,
1642
+ provider: project.provider,
1643
+ runtimeClass: selectedDescriptor.runtimeClass,
1644
+ status: 'unavailable-for-project',
1645
+ nativeWasm: false,
1646
+ providerRealityValidated: false,
1647
+ automaticFallback: false,
1648
+ error: eventSupport && eventSupport.status === 'blocked'
1649
+ ? Object.freeze({ code: eventSupport.diagnosticCode, eventTargetSupport: eventSupport })
1650
+ : nativeInspectionError
1651
+ }))
1652
+ : (javascriptApplication ? Object.freeze({
1653
+ target: selectedDescriptor.targetId,
1654
+ provider: project.provider,
1655
+ runtimeClass: selectedDescriptor.runtimeClass,
1656
+ sourceApplication: true,
1657
+ status: eventSupport && eventSupport.status === 'blocked'
1658
+ ? 'unavailable-for-project'
1659
+ : selectedDescriptor.status,
1660
+ javascriptRuntime: true,
1661
+ nativeWasm: false,
1662
+ automaticFallback: false,
1663
+ applicationPlan: Object.freeze({
1664
+ version: javascriptApplication.plan.version,
1665
+ plannerVersion: javascriptApplication.plan.plannerVersion,
1666
+ planHash: javascriptApplication.plan.planHash,
1667
+ graphHash: javascriptApplication.plan.graph.graphHash,
1668
+ loadable: javascriptApplication.plan.loadable,
1669
+ blockers: javascriptApplication.plan.blockers,
1670
+ modules: javascriptApplication.plan.graph.modules.filter((entry) => entry.runtime && entry.kind === 'project').length,
1671
+ packages: javascriptApplication.plan.packages,
1672
+ nativeEligibility: javascriptApplication.plan.nativeEligibility,
1673
+ entrySafety: javascriptApplication.plan.entrySafety
1674
+ }),
1675
+ loader: targetSupport ? Object.freeze({
1676
+ ...targetSupport.loader,
1677
+ applicationValid: targetSupport.loader.loaded === true
1678
+ || (targetSupport.loader.skippedReason === 'provider-build-time-bundle-loader'
1679
+ && javascriptApplication.plan.loadable === true)
1680
+ }) : null,
1681
+ loadError: javascriptApplication.loadError,
1682
+ supportEvidenceHash: targetSupport && targetSupport.evidenceHash,
1683
+ coreExecutionReady: targetSupport && targetSupport.availability.coreExecutionReady,
1684
+ fullTargetSupportReady: targetSupport && targetSupport.availability.fullTargetSupportReady,
1685
+ generalAvailable: targetSupport && targetSupport.availability.generalAvailable,
1686
+ projectEligibility: targetSupport && targetSupport.project.status,
1687
+ requestAdapter: selectedDescriptor.requestAdapter,
1688
+ lifecycle: selectedDescriptor.lifecycle,
1689
+ ...(eventSupport && eventSupport.status === 'blocked' ? {
1690
+ error: Object.freeze({ code: eventSupport.diagnosticCode, eventTargetSupport: eventSupport })
1691
+ } : {}),
1692
+ ...(driver.javascript && driver.javascript.localExecutionMode ? {
1693
+ localTooling: Object.freeze({
1694
+ test: driver.javascript.localExecutionMode,
1695
+ dev: driver.javascript.localExecutionMode,
1696
+ loader: 'provider-owned-bundled-closure',
1697
+ packageClosure: 'esbuild-bundled',
1698
+ providerReality: false,
1699
+ realityRunner: driver.javascript.realityRunner,
1700
+ automaticFallback: false
1701
+ }),
1702
+ deploymentCandidate: Object.freeze({
1703
+ status: 'structurally-deployable',
1704
+ emittedBy: 'pulse build',
1705
+ providerRealityValidated: false,
1706
+ deployed: false
1707
+ })
1708
+ } : {})
1709
+ }) : undefined);
1710
+ return Object.freeze({
1711
+ status: 'ok',
1712
+ version: PROJECT_EXECUTION_VERSION,
1713
+ project: projectJson(project),
1714
+ provider: Object.freeze({
1715
+ id: project.provider,
1716
+ package: driver.descriptor && driver.descriptor.package,
1717
+ buildTarget: driver.descriptor && driver.descriptor.buildTarget,
1718
+ selectedTarget,
1719
+ targetAvailability: Object.freeze({ native: effectiveAvailability.native, javascript: effectiveAvailability.javascript }),
1720
+ targetDescriptors: effectiveAvailability.descriptors,
1721
+ selectedTargetDescriptor: selectedDescriptor,
1722
+ targetSupport,
1723
+ eventTargetSupport: eventSupport,
1724
+ defaultBuildMode: driver.defaultBuildMode,
1725
+ sourceOnlySupported: false,
1726
+ realization
1727
+ }),
1728
+ plan: projectPlanInspection(project, compiled),
1729
+ compiler: Object.freeze({
1730
+ version: compiled.version,
1731
+ file: compiled.metadata.file,
1732
+ sourceHash: compiled.metadata.sourceHash,
1733
+ authoring: compiled.metadata.authoring || Object.freeze({ kind: 'handler' }),
1734
+ ...(compiled.metadata.application ? { application: compiled.metadata.application } : {}),
1735
+ ...(compiled.metadata.json ? { json: compiled.metadata.json } : {}),
1736
+ ...((compiled.metadata.warnings && compiled.metadata.warnings.length > 0) ? { warnings: compiled.metadata.warnings } : {}),
1737
+ warningCount: compiled.metadata.warningCount || 0,
1738
+ jsonPolicy: jsonPolicyInspection(project, compiled, nativePlan),
1739
+ requestState: nativePlan && nativePlan.requestState || Object.freeze({ enabled: false, representation: 'absent', reset: 'not-required' }),
1740
+ routing: nativePlan && nativePlan.routing || null,
1741
+ capabilities: compiled.metadata.capabilities,
1742
+ effects: compiled.metadata.effectSites,
1743
+ continuations: compiled.metadata.continuationSites,
1744
+ effectCount: compiled.metadata.effectCount,
1745
+ continuationCount: compiled.metadata.continuationCount,
1746
+ groupedContinuationCount: compiled.metadata.groupedContinuationCount,
1747
+ opaqueReturnCount: compiled.metadata.opaqueReturnCount,
1748
+ providerOperations: compiled.metadata.providerOperations,
1749
+ providerLowering: eventSupport && eventSupport.status === 'blocked'
1750
+ ? Object.freeze({
1751
+ status: 'blocked',
1752
+ code: eventSupport.diagnosticCode,
1753
+ eventTargetSupport: eventSupport,
1754
+ automaticFallback: false
1755
+ })
1756
+ : providerLoweringPlan(project, compiled.metadata),
1757
+ reachableGraph: Object.freeze({
1758
+ version: compiled.reachableGraph.version,
1759
+ graphHash: compiled.reachableGraph.graphHash,
1760
+ modules: compiled.reachableGraph.modules.length,
1761
+ runtimeModules: compiled.reachableGraph.modules.filter((entry) => entry.runtime).length,
1762
+ edges: compiled.reachableGraph.edges.length,
1763
+ handlers: compiled.reachableGraph.handlers.length,
1764
+ cycles: compiled.reachableGraph.cycles.length,
1765
+ unsupportedBoundaries: compiled.reachableGraph.unsupportedBoundaries.length
1766
+ }),
1767
+ packageReachability: compiled.packageReachability,
1768
+ packageProduct: compiled.packageProduct,
1769
+ packageInspection: compiled.packageInspection,
1770
+ ...(eventInspection ? { events: eventInspection } : {}),
1771
+ ...(compiled.packageApplication ? { packageApplication: compiled.packageApplication } : {}),
1772
+ applicationEntrySafety: compiled.entrySafety,
1773
+ nativeEligibility: compiled.nativeEligibility,
1774
+ native: nativePlan && native ? Object.freeze({
1775
+ status: 'available',
1776
+ target: 'portable-native-wasm',
1777
+ providerNeutral: true,
1778
+ requiredForSelectedTarget: selectedTarget === 'native',
1779
+ selectedTarget,
1780
+ automaticFallback: false,
1781
+ planVersion: nativePlan.version,
1782
+ planCompilerVersion: nativePlan.compilerVersion,
1783
+ planHash: nativePlan.planHash,
1784
+ ownership: nativePlan.ownership,
1785
+ summary: nativePlan.summary,
1786
+ ...(nativePlan.json ? { json: nativePlan.json } : {}),
1787
+ ...(nativePlan.requestState ? { requestState: nativePlan.requestState } : {}),
1788
+ compilerVersion: native.compilerVersion,
1789
+ assemblyScript: native.manifest.assemblyScript,
1790
+ wasm: native.manifest.wasm,
1791
+ wat: native.manifest.wat,
1792
+ importModules: native.manifest.importModules,
1793
+ imports: native.manifest.imports,
1794
+ exports: native.manifest.exports,
1795
+ policy: native.manifest.policy
1796
+ }) : Object.freeze({
1797
+ status: 'unavailable-for-project',
1798
+ target: 'portable-native-wasm',
1799
+ providerNeutral: true,
1800
+ requiredForSelectedTarget: selectedTarget === 'native',
1801
+ selectedTarget,
1802
+ automaticFallback: false,
1803
+ error: nativeInspectionError
1804
+ }),
1805
+ schemas: Object.freeze({
1806
+ active: compiled.schema.active,
1807
+ compilerVersion: compiled.schema.compilerVersion,
1808
+ sourceHash: compiled.metadata.schemaSourceHash,
1809
+ registry: compiled.metadata.schemaRegistry,
1810
+ references: compiled.metadata.schemaReferences,
1811
+ unused: Object.freeze(compiled.metadata.schemaIds.filter((id) => !referencedSchemaIds.has(id))),
1812
+ diagnostics: compiled.schema.diagnostics,
1813
+ warnings: compiled.schema.warnings
1814
+ })
1815
+ }),
1816
+ ...(eventInspection ? { events: eventInspection } : {}),
1817
+ testCases: project.tests.map((entry) => entry.name)
1818
+ });
1819
+ }
1820
+
1821
+ function doctorProject(project, options = {}) {
1822
+ const checks = [];
1823
+ const selectedTarget = project.target || 'native';
1824
+ const selectedTargetDescriptor = targetDescriptor(project, selectedTarget);
1825
+ const targetSupportDeclaration = options.targetSupportDeclaration || getProviderTargetSupportDeclaration(providerDriver(project), selectedTarget);
1826
+ const providerAvailability = providerTargetAvailability(providerDriver(project));
1827
+ const targetAvailability = options.targetSupportDeclaration && targetSupportDeclaration
1828
+ ? Object.freeze({ ...providerAvailability, javascript: targetSupportDeclaration.availability.generalAvailable })
1829
+ : providerAvailability;
1830
+ checks.push(Object.freeze({
1831
+ id: 'execution-target',
1832
+ status: selectedTarget === 'javascript' && targetAvailability.javascript !== true ? 'warning' : 'passed',
1833
+ message: selectedTarget === 'javascript'
1834
+ ? (targetSupportDeclaration
1835
+ ? (targetSupportDeclaration.availability.generalAvailable
1836
+ ? `${project.provider} JavaScript full target support is sealed and generally available; the selected JavaScript target remains authoritative and no automatic fallback will occur.`
1837
+ : `Core ${project.provider} JavaScript execution is ready, but general availability remains false under the full-target-support policy while ${targetSupportDeclaration.availability.summary.pending} gate(s) remain pending; no automatic fallback will occur.`)
1838
+ : selectedTargetDescriptor.applicationLoader
1839
+ ? 'The JavaScript application loader is present, but this provider does not declare full target support; no automatic fallback will occur.'
1840
+ : selectedTargetDescriptor.status === 'source-packaging-ready'
1841
+ ? 'The selected JavaScript source-packaging boundary is ready, while provider execution remains deferred; no automatic fallback will occur.'
1842
+ : 'The selected JavaScript target is recorded but not realized for this provider; no automatic fallback will occur.')
1843
+ : 'The selected native target is available.',
1844
+ detail: Object.freeze({
1845
+ selected: selectedTarget,
1846
+ native: targetAvailability.native,
1847
+ javascript: targetAvailability.javascript,
1848
+ descriptor: selectedTargetDescriptor,
1849
+ targetSupport: targetSupportDeclaration,
1850
+ automaticFallback: false
1851
+ })
1852
+ }));
1853
+ function check(id, status, message, detail = {}, explicitCode) {
1854
+ const code = explicitCode || detail.code;
1855
+ const descriptor = code ? describeDiagnostic(code) : undefined;
1856
+ checks.push(Object.freeze({
1857
+ id,
1858
+ status,
1859
+ message,
1860
+ code,
1861
+ title: descriptor && descriptor.title,
1862
+ summary: descriptor && descriptor.summary,
1863
+ category: descriptor && descriptor.category,
1864
+ remediation: descriptor && descriptor.remediation,
1865
+ stability: descriptor && descriptor.stability,
1866
+ scope: descriptor && descriptor.scope,
1867
+ docs: descriptor && descriptor.docs,
1868
+ detail
1869
+ }));
1870
+ }
1871
+ const nodeSupported = nodeVersionSatisfiesEngines(process.versions.node, releaseNode.nodeEngines);
1872
+ check(
1873
+ 'node-version',
1874
+ nodeSupported ? 'passed' : 'failed',
1875
+ `Node ${process.versions.node}`,
1876
+ {
1877
+ engines: releaseNode.nodeEngines,
1878
+ minimumVersion: releaseNode.nodeMinimumVersion,
1879
+ sealRange: releaseNode.nodeReleaseRange,
1880
+ reproducibleToolchainVersion: releaseNode.nodeVersion
1881
+ },
1882
+ nodeSupported ? undefined : 'PULSE_NODE_VERSION_UNSUPPORTED'
1883
+ );
1884
+ check('config', project.configFile ? 'passed' : 'warning', project.configFile ? `Loaded ${relative(project.configFile, project.root)}` : 'No config file; using explicit entry defaults.', {}, project.configFile ? undefined : 'PULSE_CONFIG_IMPLICIT');
1885
+ check('entry', fs.existsSync(project.entryFile) ? 'passed' : 'failed', relative(project.entryFile, project.root), { file: relative(project.entryFile, project.root) }, fs.existsSync(project.entryFile) ? undefined : 'PULSE_ENTRY_NOT_FOUND');
1886
+ if (project.profilePlan) {
1887
+ check('project-plan', 'passed', `Selected profile ${project.profile.name} from ${project.profile.source} with plan ${String(project.planHash).slice(0, 12)}…`, projectPlanInspection(project));
1888
+ }
1889
+ let compiled;
1890
+ let nativePrepared;
1891
+ let preparedJavascript;
1892
+ let targetSupport;
1893
+ let eventSupport;
1894
+ let eventInspection;
1895
+ try {
1896
+ compiled = compileProject(project);
1897
+ check('canonical-compile', (compiled.metadata.warningCount || 0) > 0 ? 'warning' : 'passed', `Canonical source lowered with ${compiled.metadata.effectCount} effect(s), ${compiled.metadata.continuationCount} continuation(s), and ${compiled.metadata.warningCount || 0} warning(s).`, { capabilities: compiled.metadata.capabilities, warnings: compiled.metadata.warnings || [] });
1898
+ eventSupport = selectedEventTargetSupport(project, compiled, selectedTargetDescriptor);
1899
+ if (eventSupport) {
1900
+ eventInspection = eventInspectionProjection(project, compiled, eventSupport);
1901
+ check(
1902
+ 'events',
1903
+ eventSupport.status === 'eligible' ? 'passed' : (eventSupport.status === 'inspection-only' ? 'warning' : 'failed'),
1904
+ eventSupport.status === 'eligible'
1905
+ ? `The ${project.provider}/${selectedTarget} target satisfies ${eventSupport.requirements.length} reachable event requirement(s).`
1906
+ : eventSupport.status === 'inspection-only'
1907
+ ? 'The event catalog is available for compile-only inspection; no execution provider is selected.'
1908
+ : `The ${project.provider}/${selectedTarget} target cannot realize the reachable event plane and no fallback will occur.`,
1909
+ eventInspection,
1910
+ eventSupport.status === 'blocked' ? eventSupport.diagnosticCode : undefined
1911
+ );
1912
+ }
1913
+ const referencedSchemaIds = new Set(compiled.metadata.schemaReferences.map((entry) => entry.id));
1914
+ for (const schemaId of eventInspection && eventInspection.schemas.all || []) referencedSchemaIds.add(schemaId);
1915
+ const unusedSchemaIds = compiled.metadata.schemaIds.filter((id) => !referencedSchemaIds.has(id));
1916
+ check(
1917
+ 'schemas',
1918
+ unusedSchemaIds.length > 0 ? 'warning' : 'passed',
1919
+ compiled.schema.active
1920
+ ? `Compiled ${compiled.metadata.schemaIds.length} JSON schema(s) with ${compiled.metadata.schemaReferenceCount} linked HTTP handler reference(s) and ${eventInspection ? eventInspection.schemas.all.length : 0} linked event schema(s).`
1921
+ : 'No explicit JSON schemas are configured.',
1922
+ {
1923
+ ids: compiled.metadata.schemaIds,
1924
+ references: compiled.metadata.schemaReferences,
1925
+ eventReferences: eventInspection ? eventInspection.schemas.all : Object.freeze([]),
1926
+ unused: unusedSchemaIds,
1927
+ sourceHash: compiled.metadata.schemaSourceHash,
1928
+ dependencies: compiled.watchFiles.map((file) => relative(file, project.root))
1929
+ }
1930
+ );
1931
+ const jsonPolicy = jsonPolicyInspection(project, compiled);
1932
+ check(
1933
+ 'json-policy',
1934
+ 'passed',
1935
+ jsonPolicy.genericParserRequired
1936
+ ? `Non-strict schema-less JSON is enabled for ${jsonPolicy.genericRequestCount} reachable call(s); native realization uses the explicit host generic parser path.`
1937
+ : (jsonPolicy.strict ? 'Strict schema-bound JSON policy is active.' : 'Non-strict JSON policy is active, but no schema-less JSON call is reachable.'),
1938
+ jsonPolicy
1939
+ );
1940
+ nativePrepared = compileNativeProjectInMemory(project, { compiled });
1941
+ if (nativePrepared.plan.requestState && nativePrepared.plan.requestState.enabled) {
1942
+ check('request-state', 'passed', 'Request-local ctx.state is guest-owned, survives continuations, and resets at pulse_start.', nativePrepared.plan.requestState);
1943
+ }
1944
+ check(
1945
+ 'canonical-native-plan',
1946
+ 'passed',
1947
+ `Provider-neutral native plan ${nativePrepared.plan.planHash.slice(0, 12)}… contains ${nativePrepared.plan.summary.statementCount} statement(s).`,
1948
+ {
1949
+ version: nativePrepared.plan.version,
1950
+ compilerVersion: nativePrepared.plan.compilerVersion,
1951
+ planHash: nativePrepared.plan.planHash,
1952
+ ownership: nativePrepared.plan.ownership,
1953
+ summary: nativePrepared.plan.summary
1954
+ }
1955
+ );
1956
+ check(
1957
+ 'canonical-native-wasm',
1958
+ 'passed',
1959
+ `Compiled ${nativePrepared.native.manifest.wasm.bytes} bytes of provider-neutral Pulse Wasm with AssemblyScript ${nativePrepared.native.manifest.assemblyScript.version}.`,
1960
+ {
1961
+ version: nativePrepared.native.version,
1962
+ compilerVersion: nativePrepared.native.compilerVersion,
1963
+ assemblyScript: nativePrepared.native.manifest.assemblyScript,
1964
+ wasm: nativePrepared.native.manifest.wasm,
1965
+ importModules: nativePrepared.native.manifest.importModules,
1966
+ planHash: nativePrepared.plan.planHash
1967
+ }
1968
+ );
1969
+ } catch (error) {
1970
+ const nativeFailure = error && ['PULSE_CANONICAL_NATIVE_PLAN_FAILED', 'PULSE_CANONICAL_NATIVE_AS_GENERATION_FAILED', 'PULSE_CANONICAL_NATIVE_COMPILE_FAILED'].includes(error.code);
1971
+ if (nativeFailure && compiled) {
1972
+ const selectedTargetRequiresNative = selectedTarget === 'native';
1973
+ check(
1974
+ error.code === 'PULSE_CANONICAL_NATIVE_PLAN_FAILED' ? 'canonical-native-plan' : 'canonical-native-wasm',
1975
+ selectedTargetRequiresNative ? 'failed' : 'warning',
1976
+ selectedTargetRequiresNative
1977
+ ? error.message
1978
+ : `Provider-neutral native realization is unavailable for this project, but the selected JavaScript target is inspected independently and no native fallback will occur: ${error.message}`,
1979
+ {
1980
+ code: error.code,
1981
+ diagnostics: error.diagnostics,
1982
+ detail: error.detail,
1983
+ selectedTarget,
1984
+ requiredForSelectedTarget: selectedTargetRequiresNative,
1985
+ automaticFallback: false
1986
+ }
1987
+ );
1988
+ } else {
1989
+ check('canonical-compile', 'failed', error.message, { code: error.code, diagnostics: error.diagnostics });
1990
+ }
1991
+ const schemaFailure = error.code === 'PULSE_SCHEMA_COMPILE_FAILED' || (error.diagnostics || []).some((entry) => String(entry.code || '').includes('SCHEMA'));
1992
+ if (schemaFailure) check('schemas', 'failed', error.message, { code: error.code, diagnostics: error.diagnostics, detail: error.detail });
1993
+ }
1994
+ if (selectedTarget === 'javascript') {
1995
+ try {
1996
+ const javascript = providerDriver(project).javascript;
1997
+ preparedJavascript = prepareJavascriptApplication(project, { captureLoadError: true });
1998
+ targetSupport = selectedTargetSupportEvidence(project, compiled, preparedJavascript, selectedTargetDescriptor, options);
1999
+ const applicationDecision = targetSupport && targetSupport.project.application.find((entry) => entry.id === 'application.plan');
2000
+ const buildTimeLoaderReady = javascript && javascript.buildTimeLoader === true
2001
+ && preparedJavascript.plan.loadable === true
2002
+ && targetSupport
2003
+ && targetSupport.loader.skippedReason === 'provider-build-time-bundle-loader'
2004
+ && targetSupport.project.status === 'eligible';
2005
+ const applicationStatus = applicationDecision && applicationDecision.status === 'pending'
2006
+ ? 'warning'
2007
+ : preparedJavascript.loaded || buildTimeLoaderReady
2008
+ ? 'passed'
2009
+ : targetSupport && targetSupport.project.status === 'pending'
2010
+ ? 'warning'
2011
+ : 'failed';
2012
+ const applicationMessage = applicationDecision && applicationDecision.status === 'pending'
2013
+ ? `The JavaScript application graph is deterministic, but reachable package realization remains pending for ${targetSupport.project.reasonIds.join(', ')}.`
2014
+ : preparedJavascript.loaded
2015
+ ? `Graph-backed JavaScript application ${preparedJavascript.plan.planHash.slice(0, 12)}… loaded ${preparedJavascript.loaded.modulesLoaded} project module(s).`
2016
+ : buildTimeLoaderReady
2017
+ ? `${project.provider} JavaScript application ${preparedJavascript.plan.planHash.slice(0, 12)}… is loadable through the deterministic build-time bundle loader and available to explicit local provider emulation.`
2018
+ : targetSupport && targetSupport.project.status === 'pending'
2019
+ ? `The JavaScript application graph is deterministic, but reachable package/capability realization remains pending for ${targetSupport.project.reasonIds.join(', ')}.`
2020
+ : (preparedJavascript.loadError
2021
+ ? `The JavaScript application loader failed: ${preparedJavascript.loadError.message}`
2022
+ : 'The JavaScript application plan is blocked for the selected target.');
2023
+ check(
2024
+ 'javascript-application',
2025
+ applicationStatus,
2026
+ applicationMessage,
2027
+ {
2028
+ target: preparedJavascript.descriptor,
2029
+ planVersion: preparedJavascript.plan.version,
2030
+ planHash: preparedJavascript.plan.planHash,
2031
+ graphHash: preparedJavascript.plan.graph.graphHash,
2032
+ loadable: preparedJavascript.plan.loadable,
2033
+ blockers: preparedJavascript.plan.blockers,
2034
+ packages: preparedJavascript.plan.packages,
2035
+ nativeEligibility: preparedJavascript.plan.nativeEligibility,
2036
+ entrySafety: preparedJavascript.plan.entrySafety,
2037
+ loader: preparedJavascript.loaded ? {
2038
+ version: preparedJavascript.loaded.version,
2039
+ modulesLoaded: preparedJavascript.loaded.modulesLoaded,
2040
+ packagesLoaded: preparedJavascript.loaded.packagesLoaded
2041
+ } : null,
2042
+ loadError: preparedJavascript.loadError,
2043
+ targetSupportEvidenceHash: targetSupport && targetSupport.evidenceHash,
2044
+ projectEligibility: targetSupport && targetSupport.project.status,
2045
+ automaticFallback: false
2046
+ },
2047
+ applicationStatus === 'passed'
2048
+ ? undefined
2049
+ : targetSupport && targetSupport.project.packages.find((entry) => entry.required && entry.status === 'pending' && entry.reasonCode)?.reasonCode
2050
+ || preparedJavascript.plan.blockers[0]?.code
2051
+ || preparedJavascript.loadError?.code
2052
+ || 'PULSE_TARGET_IMPLEMENTATION_PENDING'
2053
+ );
2054
+ if (targetSupport) {
2055
+ const pendingProjectItems = targetSupport.project.summary.application.pending
2056
+ + targetSupport.project.summary.capabilities.pending
2057
+ + targetSupport.project.summary.providerRequirements.pending
2058
+ + targetSupport.project.summary.packages.pending;
2059
+ const blockedProjectItems = targetSupport.project.summary.application.blocked
2060
+ + targetSupport.project.summary.capabilities.blocked
2061
+ + targetSupport.project.summary.providerRequirements.blocked
2062
+ + targetSupport.project.summary.packages.blocked;
2063
+ check(
2064
+ 'target-support',
2065
+ targetSupport.project.status === 'blocked'
2066
+ ? 'failed'
2067
+ : targetSupport.project.status === 'eligible' && targetSupport.availability.generalAvailable
2068
+ ? 'passed'
2069
+ : 'warning',
2070
+ targetSupport.project.status === 'eligible'
2071
+ ? (targetSupport.availability.generalAvailable
2072
+ ? `This project is eligible for the sealed and generally available ${project.provider} JavaScript target; the selected target remains authoritative and automatic fallback is disabled.`
2073
+ : `This project is eligible for the sealed core ${project.provider} JavaScript lane, but general availability remains false until ${targetSupport.availability.summary.pending} full-support gate(s) close.`)
2074
+ : targetSupport.project.status === 'pending'
2075
+ ? (targetSupport.availability.generalAvailable
2076
+ ? `The ${project.provider} JavaScript target is generally available, but this project has ${pendingProjectItems} pending capability/package decision(s) and is not yet eligible.`
2077
+ : `This project has ${pendingProjectItems} pending JavaScript capability/package decision(s); general availability also remains false under the full-target-support policy.`)
2078
+ : `This project has ${blockedProjectItems} blocked JavaScript capability/package decision(s) and cannot execute on the selected target.`,
2079
+ targetSupport
2080
+ );
2081
+ }
2082
+ if (javascript && javascript.localExecutionMode) {
2083
+ check(
2084
+ 'javascript-local-tooling',
2085
+ 'passed',
2086
+ `pulse test and pulse dev use explicit ${project.provider} provider emulation; provider reality remains a separate ${javascript.realityRunner} step.`,
2087
+ {
2088
+ mode: javascript.localExecutionMode,
2089
+ loader: 'provider-owned-bundled-closure',
2090
+ packageClosure: 'esbuild-bundled',
2091
+ providerReality: false,
2092
+ realityRunner: javascript.realityRunner,
2093
+ deploymentCandidate: 'pulse build',
2094
+ automaticFallback: false
2095
+ }
2096
+ );
2097
+ }
2098
+ } catch (error) {
2099
+ check('javascript-application', 'failed', error.message, { code: error.code, detail: error.detail, diagnostics: error.diagnostics }, error.code);
2100
+ }
2101
+ }
2102
+ const driver = providerDriver(project);
2103
+ if (!driver.executable) check('provider', 'warning', 'Compile-only provider selected; pulse build, dev, and test are unavailable. Use pulse compile for provider-neutral Wasm.', { provider: project.provider }, 'PULSE_PROVIDER_COMPILE_ONLY');
2104
+ else {
2105
+ try {
2106
+ const lowering = compiled ? driver.createLoweringPlan(compiled.metadata, project.providerConfig) : undefined;
2107
+ check('provider', selectedTarget === 'javascript' && targetAvailability.javascript !== true ? 'warning' : 'passed', selectedTarget === 'javascript'
2108
+ ? (targetSupportDeclaration
2109
+ ? (targetSupportDeclaration.availability.generalAvailable
2110
+ ? `${project.provider} JavaScript full target support is sealed and generally available; bounded GRIP realization is included and automatic fallback remains disabled.`
2111
+ : `${project.provider} JavaScript core execution and bounded GRIP realization are ready, but one or more full-target-support gates remain pending, so general availability remains false.`)
2112
+ : `${project.provider} JavaScript application loading is not declared as a fully supported target.`)
2113
+ : `${project.provider} native provider contract and local conformance runtime are available.`, {
2114
+ package: driver.descriptor.package,
2115
+ buildTarget: driver.descriptor.buildTarget,
2116
+ deployable: driver.deployable === true,
2117
+ deploymentValidated: driver.deploymentValidated === true,
2118
+ sourcePackage: driver.sourcePackage === true,
2119
+ compiledWasm: driver.compiledWasm === true,
2120
+ selectedTarget,
2121
+ targetAvailability: Object.freeze({ native: targetAvailability.native, javascript: targetAvailability.javascript }),
2122
+ targetDescriptors: targetAvailability.descriptors,
2123
+ selectedTargetDescriptor,
2124
+ targetSupportDeclaration,
2125
+ targetSupportEvidenceHash: targetSupport && targetSupport.evidenceHash,
2126
+ defaultBuildMode: driver.defaultBuildMode,
2127
+ sourceOnlySupported: false,
2128
+ localExecution: driver.localExecution === true,
2129
+ requirements: lowering && lowering.requirements
2130
+ });
2131
+ } catch (error) {
2132
+ check('provider', 'failed', error.message, { code: error.code, detail: error.detail });
2133
+ }
2134
+ }
2135
+ if (selectedTarget === 'native' && nativePrepared && driver.executable && driver.inspectRealization && (!eventSupport || eventSupport.status !== 'blocked')) {
2136
+ try {
2137
+ const realization = normalizeProviderTargetResult(driver.inspectRealization(providerTargetInvocation(
2138
+ project,
2139
+ 'inspect-native',
2140
+ nativePrepared.plan,
2141
+ providerLoweringPlan(project, nativePrepared.compiled.metadata),
2142
+ {
2143
+ native: nativePrepared.native,
2144
+ optimization: nativePrepared.native.manifest.optimization,
2145
+ timeoutMs: options.timeoutMs
2146
+ }
2147
+ )), { action: 'inspect-native', provider: project.provider, target: 'native' }).realization;
2148
+ check(
2149
+ 'provider-native-realization',
2150
+ 'passed',
2151
+ `${project.provider} realizes the portable plan as ${realization.wasm.bytes} bytes of native provider Wasm.`,
2152
+ {
2153
+ target: realization.target,
2154
+ provider: project.provider,
2155
+ nativeWasm: realization.nativeWasm === true,
2156
+ javascriptRuntime: realization.javascriptRuntime === true,
2157
+ jsComputeRuntime: realization.jsComputeRuntime === true,
2158
+ compiler: realization.compiler,
2159
+ wasm: realization.wasm,
2160
+ importModules: realization.importModules,
2161
+ imports: realization.imports,
2162
+ exports: realization.exports,
2163
+ policy: realization.policy
2164
+ }
2165
+ );
2166
+ } catch (error) {
2167
+ check('provider-native-realization', 'failed', error.message, { code: error.code, detail: error.detail, diagnostics: error.diagnostics });
2168
+ }
2169
+ }
2170
+ try {
2171
+ const output = resolveOutputDirectory(project, project.outDir);
2172
+ check('build-output', 'passed', relative(output, project.root));
2173
+ } catch (error) {
2174
+ check('build-output', 'failed', error.message, { code: error.code, outDir: project.outDir });
2175
+ }
2176
+ if (driver.executable && project.dev.networkFetch) {
2177
+ check('network-fetch', typeof globalThis.fetch === 'function' ? 'passed' : 'failed', typeof globalThis.fetch === 'function' ? `${project.provider} local live fetch is available for pulse dev.` : 'Local live fetch is unavailable.', { enabled: true, provider: project.provider }, typeof globalThis.fetch === 'function' ? undefined : 'PULSE_FETCH_IMPLEMENTATION_UNAVAILABLE');
2178
+ } else {
2179
+ check('network-fetch', 'passed', project.dev.networkFetch ? 'Provider owns outbound fetch.' : 'Live network fetch is disabled; configured fixtures are required.', { enabled: project.dev.networkFetch });
2180
+ }
2181
+ check('tests', project.tests.length > 0 ? 'passed' : 'warning', project.tests.length > 0 ? `${project.tests.length} project test case(s) configured.` : 'No project test cases configured.', { count: project.tests.length }, project.tests.length > 0 ? undefined : 'PULSE_TEST_CASES_MISSING');
2182
+ const failed = checks.filter((entry) => entry.status === 'failed').length;
2183
+ const warnings = checks.filter((entry) => entry.status === 'warning').length;
2184
+ const ok = failed === 0 && (!options.strict || warnings === 0);
2185
+ return Object.freeze({
2186
+ status: ok ? (warnings > 0 ? 'warning' : 'passed') : 'failed',
2187
+ version: PROJECT_EXECUTION_VERSION,
2188
+ project: projectJson(project),
2189
+ summary: Object.freeze({ total: checks.length, passed: checks.filter((entry) => entry.status === 'passed').length, warnings, failed }),
2190
+ checks: Object.freeze(checks),
2191
+ targetSupport,
2192
+ ...(eventSupport ? { events: eventInspectionProjection(project, compiled, eventSupport) } : {}),
2193
+ metadata: compiled && compiled.metadata
2194
+ });
2195
+ }
2196
+
2197
+ async function readRequestBody(req, maxBytes) {
2198
+ const chunks = [];
2199
+ let bytes = 0;
2200
+ for await (const chunk of req) {
2201
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
2202
+ bytes += buffer.byteLength;
2203
+ if (bytes > maxBytes) throw new PulseProjectError('PULSE_REQUEST_BODY_TOO_LARGE', `Request body exceeds ${maxBytes} bytes.`, { maxBytes, bytes });
2204
+ chunks.push(buffer);
2205
+ }
2206
+ return Buffer.concat(chunks).toString('utf8');
2207
+ }
2208
+
2209
+ function requestHeaders(req) {
2210
+ if (Array.isArray(req.rawHeaders) && req.rawHeaders.length > 0) {
2211
+ const pairs = [];
2212
+ for (let index = 0; index < req.rawHeaders.length; index += 2) pairs.push([req.rawHeaders[index], req.rawHeaders[index + 1] || '']);
2213
+ return pairs;
2214
+ }
2215
+ return Object.entries(req.headers || {}).flatMap(([name, value]) => Array.isArray(value) ? value.map((entry) => [name, entry]) : [[name, value === undefined ? '' : value]]);
2216
+ }
2217
+
2218
+ function devErrorResponse(res, error, secrets) {
2219
+ if (res.headersSent) {
2220
+ if (!res.writableEnded) res.end();
2221
+ return;
2222
+ }
2223
+ const summary = errorSummary(error, secrets);
2224
+ res.statusCode = httpStatusForDiagnostic(summary.code, 500);
2225
+ res.setHeader('content-type', 'application/json; charset=utf-8');
2226
+ res.end(stableJson({
2227
+ error: summary.name,
2228
+ code: summary.code,
2229
+ category: summary.category,
2230
+ message: summary.message,
2231
+ remediation: summary.remediation,
2232
+ docs: summary.docs
2233
+ }));
2234
+ }
2235
+
2236
+
2237
+ function javascriptProjectWatchFiles(project, prepared, compiled) {
2238
+ const files = new Set();
2239
+ if (project.configFile) files.add(path.resolve(project.configFile));
2240
+ for (const module of prepared.plan.graph.modules || []) {
2241
+ if (module.kind === 'project' && module.path) files.add(path.resolve(project.root, module.path));
2242
+ }
2243
+ for (const file of compiled && compiled.watchFiles || []) files.add(path.resolve(file));
2244
+ return Object.freeze([...files].sort());
2245
+ }
2246
+
2247
+ async function writeJavascriptWebResponse(response, res, method = 'GET') {
2248
+ res.statusCode = response.status;
2249
+ const grouped = new Map();
2250
+ for (const [name, value] of response.headers.entries()) {
2251
+ const key = String(name).toLowerCase();
2252
+ if (!grouped.has(key)) grouped.set(key, []);
2253
+ grouped.get(key).push(String(value));
2254
+ }
2255
+ if (typeof response.headers.getSetCookie === 'function') {
2256
+ const cookies = response.headers.getSetCookie();
2257
+ if (cookies.length > 0) grouped.set('set-cookie', cookies);
2258
+ }
2259
+ for (const [name, values] of grouped) res.setHeader(name, values.length === 1 ? values[0] : values);
2260
+ if (String(method).toUpperCase() === 'HEAD' || !statusAllowsResponseBody(response.status) || !response.body) {
2261
+ if (response.body && typeof response.body.cancel === 'function') {
2262
+ try { await response.body.cancel(); } catch (_) { /* Best-effort local stream cleanup. */ }
2263
+ }
2264
+ res.end();
2265
+ return;
2266
+ }
2267
+ res.end(Buffer.from(await response.arrayBuffer()));
2268
+ }
2269
+
2270
+ async function startBundledJavascriptDevServer(project, options = {}) {
2271
+ const descriptor = assertImplementedTarget(project, 'dev');
2272
+ const javascript = providerDriver(project).javascript;
2273
+ if (
2274
+ !javascript
2275
+ || typeof javascript.createLocalEnvironment !== 'function'
2276
+ || typeof javascript.createTestRequest !== 'function'
2277
+ || typeof javascript.executeLocalRequest !== 'function'
2278
+ || descriptor.requestAdapter !== true
2279
+ || descriptor.lifecycle !== true
2280
+ ) {
2281
+ throw new PulseProjectError(
2282
+ 'PULSE_TARGET_IMPLEMENTATION_PENDING',
2283
+ 'pulse dev cannot realize the selected provider-bundled JavaScript target yet.',
2284
+ { target: 'javascript', provider: project.provider, targetDescriptor: descriptor, automaticFallback: false }
2285
+ );
2286
+ }
2287
+
2288
+ let prepared;
2289
+ let application;
2290
+ let compileError;
2291
+ let schemaCodecs;
2292
+ let reloadTimer;
2293
+ const watchEnabled = project.dev.watch && options.watch !== false;
2294
+ const watched = new Map();
2295
+ const events = typeof options.onEvent === 'function' ? options.onEvent : () => {};
2296
+ const environment = javascript.createLocalEnvironment({
2297
+ bindings: project.providerConfig.bindings,
2298
+ config: project.dev.config,
2299
+ secrets: project.dev.secrets,
2300
+ kv: project.dev.kv,
2301
+ fetches: project.dev.fetches,
2302
+ networkFetch: project.dev.networkFetch,
2303
+ fetchImplementation: project.dev.networkFetch ? globalThis.fetch : undefined
2304
+ });
2305
+
2306
+ function syncWatchFiles(files) {
2307
+ if (!watchEnabled) return;
2308
+ const desired = new Set((files || []).map((file) => path.resolve(file)));
2309
+ for (const [file, listener] of watched) {
2310
+ if (desired.has(file)) continue;
2311
+ fs.unwatchFile(file, listener);
2312
+ watched.delete(file);
2313
+ }
2314
+ for (const file of desired) {
2315
+ if (watched.has(file)) continue;
2316
+ const listener = scheduleReload;
2317
+ fs.watchFile(file, { interval: 200 }, listener);
2318
+ watched.set(file, listener);
2319
+ }
2320
+ }
2321
+
2322
+ function reload(reason) {
2323
+ try {
2324
+ const nextCompiled = compileProject(project);
2325
+ const next = prepareJavascriptApplication(project, {
2326
+ allowedPackages: options.allowedPackages,
2327
+ localEmulation: true,
2328
+ schemaBundle: nextCompiled.schema.bundle
2329
+ });
2330
+ if (!next.loaded) {
2331
+ throw new PulseProjectError(
2332
+ 'PULSE_JAVASCRIPT_APPLICATION_UNAVAILABLE',
2333
+ 'The graph-backed JavaScript application could not be loaded for local provider emulation.',
2334
+ { planHash: next.plan.planHash, blockers: next.plan.blockers, automaticFallback: false }
2335
+ );
2336
+ }
2337
+ prepared = next;
2338
+ application = next.loaded.application;
2339
+ schemaCodecs = createCanonicalSchemaCodecs(nextCompiled.schema.bundle.registry);
2340
+ compileError = undefined;
2341
+ const watchFiles = javascriptProjectWatchFiles(project, next, nextCompiled);
2342
+ syncWatchFiles(watchFiles);
2343
+ events(Object.freeze({
2344
+ event: reason === 'initial' ? 'compiled' : 'reloaded',
2345
+ provider: project.provider,
2346
+ target: 'javascript',
2347
+ targetId: descriptor.targetId,
2348
+ executionMode: javascript.localExecutionMode,
2349
+ providerReality: false,
2350
+ entry: relative(project.entryFile, project.root),
2351
+ planHash: next.plan.planHash,
2352
+ graphHash: next.plan.graph.graphHash,
2353
+ localClosureHash: next.loaded.closure.sourceHash,
2354
+ bundledInputs: next.loaded.closure.inputs.length,
2355
+ packagesLoaded: next.loaded.packagesLoaded,
2356
+ watchFiles: Object.freeze(watchFiles.map((file) => relative(file, project.root)))
2357
+ }));
2358
+ } catch (error) {
2359
+ if (!application) compileError = error;
2360
+ events(Object.freeze({
2361
+ event: 'compile-error',
2362
+ provider: project.provider,
2363
+ target: 'javascript',
2364
+ executionMode: javascript.localExecutionMode,
2365
+ retainedLastGoodProgram: Boolean(application),
2366
+ error: errorSummary(error, project.dev.secrets)
2367
+ }));
2368
+ }
2369
+ }
2370
+
2371
+ function scheduleReload() {
2372
+ if (reloadTimer) clearTimeout(reloadTimer);
2373
+ reloadTimer = setTimeout(() => {
2374
+ reloadTimer = undefined;
2375
+ reload('change');
2376
+ }, 60);
2377
+ }
2378
+
2379
+ reload('initial');
2380
+ if (compileError) throw compileError;
2381
+
2382
+ let handled = 0;
2383
+ const structuredBodyLimit = project.schemas.active
2384
+ ? Math.min(project.dev.maxBodyBytes, project.schemas.maxBytes)
2385
+ : project.dev.maxBodyBytes;
2386
+ const server = http.createServer(async (req, res) => {
2387
+ if (options.once) res.once('finish', () => server.close());
2388
+ try {
2389
+ if (compileError) throw compileError;
2390
+ const body = await readRequestBody(req, structuredBodyLimit);
2391
+ const host = req.headers.host || `${project.dev.host}:${project.dev.port}`;
2392
+ const url = new URL(req.url || '/', `http://${host}`);
2393
+ const request = javascript.createTestRequest({
2394
+ method: req.method || 'GET',
2395
+ url: url.href,
2396
+ path: url.pathname,
2397
+ headers: requestHeaders(req),
2398
+ body: body || undefined
2399
+ });
2400
+ const execution = await javascript.executeLocalRequest(application, request, {
2401
+ environment,
2402
+ bindings: project.providerConfig.bindings,
2403
+ application: Object.freeze({
2404
+ projectHash: project.projectHash,
2405
+ planHash: project.planHash,
2406
+ profile: project.profile,
2407
+ target: 'javascript',
2408
+ provider: project.provider
2409
+ }),
2410
+ maxBodyBytes: structuredBodyLimit,
2411
+ maxRequestBodyBytes: structuredBodyLimit,
2412
+ maxFetchBodyBytes: structuredBodyLimit,
2413
+ schemaCodecs,
2414
+ strict: project.strict !== false,
2415
+ reporting: project.reporting
2416
+ });
2417
+ await writeJavascriptWebResponse(execution.response, res, req.method || 'GET');
2418
+ handled += 1;
2419
+ events(Object.freeze({
2420
+ event: 'request',
2421
+ provider: project.provider,
2422
+ target: 'javascript',
2423
+ executionMode: javascript.localExecutionMode,
2424
+ providerReality: false,
2425
+ requestId: `dev:${handled}`,
2426
+ method: req.method || 'GET',
2427
+ path: url.pathname,
2428
+ status: execution.response.status,
2429
+ effects: execution.effectSummary ? execution.effectSummary.ownedEffectCount : 0
2430
+ }));
2431
+ } catch (error) {
2432
+ devErrorResponse(res, error, project.dev.secrets);
2433
+ events(Object.freeze({
2434
+ event: 'request-error',
2435
+ provider: project.provider,
2436
+ target: 'javascript',
2437
+ executionMode: javascript.localExecutionMode,
2438
+ method: req.method || 'GET',
2439
+ path: req.url || '/',
2440
+ error: errorSummary(error, project.dev.secrets)
2441
+ }));
2442
+ }
2443
+ });
2444
+
2445
+ function cleanup() {
2446
+ if (reloadTimer) clearTimeout(reloadTimer);
2447
+ for (const [file, listener] of watched) fs.unwatchFile(file, listener);
2448
+ watched.clear();
2449
+ }
2450
+ server.once('close', cleanup);
2451
+ server.once('error', cleanup);
2452
+ const listenHost = options.host || project.dev.host;
2453
+ const listenPort = options.port !== undefined ? Number(options.port) : project.dev.port;
2454
+ server.listen(listenPort, listenHost);
2455
+ await once(server, 'listening');
2456
+ const address = server.address();
2457
+ const boundHost = typeof address === 'object' && address ? address.address : listenHost;
2458
+ const boundPort = typeof address === 'object' && address ? address.port : listenPort;
2459
+ const advertisedHost = listenHost === '0.0.0.0' || listenHost === '::' ? '127.0.0.1' : listenHost;
2460
+ const urlHost = advertisedHost.includes(':') ? `[${advertisedHost}]` : advertisedHost;
2461
+ const ready = Object.freeze({
2462
+ event: 'ready',
2463
+ version: PROJECT_EXECUTION_VERSION,
2464
+ provider: project.provider,
2465
+ target: 'javascript',
2466
+ targetId: descriptor.targetId,
2467
+ runtimeClass: descriptor.runtimeClass,
2468
+ executionMode: javascript.localExecutionMode,
2469
+ providerReality: false,
2470
+ realityRunner: javascript.realityRunner,
2471
+ host: boundHost,
2472
+ port: boundPort,
2473
+ url: `http://${urlHost}:${boundPort}`,
2474
+ watch: watched.size > 0,
2475
+ watchFiles: Object.freeze([...watched.keys()].map((file) => relative(file, project.root))),
2476
+ once: Boolean(options.once),
2477
+ applicationPlan: Object.freeze({ planHash: prepared.plan.planHash, graphHash: prepared.plan.graph.graphHash }),
2478
+ localLoader: Object.freeze({
2479
+ version: prepared.loaded.version,
2480
+ kind: 'provider-owned-bundled-closure',
2481
+ sourceHash: prepared.loaded.closure.sourceHash,
2482
+ bundledInputs: prepared.loaded.closure.inputs.length,
2483
+ packagesLoaded: prepared.loaded.packagesLoaded
2484
+ }),
2485
+ automaticFallback: false,
2486
+ project: projectJson(project)
2487
+ });
2488
+ events(ready);
2489
+ return Object.freeze({ server, ready, closed: once(server, 'close') });
2490
+ }
2491
+
2492
+ async function startJavascriptDevServer(project, options = {}) {
2493
+ const javascript = providerDriver(project).javascript;
2494
+ if (javascript && javascript.kind === 'provider-bundled') return startBundledJavascriptDevServer(project, options);
2495
+ const descriptor = assertImplementedTarget(project, 'dev');
2496
+ if (!javascript || typeof javascript.createServer !== 'function' || descriptor.requestAdapter !== true || descriptor.lifecycle !== true) {
2497
+ throw new PulseProjectError(
2498
+ 'PULSE_TARGET_IMPLEMENTATION_PENDING',
2499
+ `pulse dev cannot realize the selected javascript target for ${project.provider} yet.`,
2500
+ { target: 'javascript', provider: project.provider, targetDescriptor: descriptor, automaticFallback: false }
2501
+ );
2502
+ }
2503
+
2504
+ let prepared;
2505
+ let application;
2506
+ let compileError;
2507
+ let schemaCodecs;
2508
+ let reloadTimer;
2509
+ const watchEnabled = project.dev.watch && options.watch !== false;
2510
+ const watched = new Map();
2511
+ const events = typeof options.onEvent === 'function' ? options.onEvent : () => {};
2512
+
2513
+ function syncWatchFiles(files) {
2514
+ if (!watchEnabled) return;
2515
+ const desired = new Set((files || []).map((file) => path.resolve(file)));
2516
+ for (const [file, listener] of watched) {
2517
+ if (desired.has(file)) continue;
2518
+ fs.unwatchFile(file, listener);
2519
+ watched.delete(file);
2520
+ }
2521
+ for (const file of desired) {
2522
+ if (watched.has(file)) continue;
2523
+ const listener = scheduleReload;
2524
+ fs.watchFile(file, { interval: 200 }, listener);
2525
+ watched.set(file, listener);
2526
+ }
2527
+ }
2528
+
2529
+ function reload(reason) {
2530
+ try {
2531
+ const next = prepareJavascriptApplication(project, { allowedPackages: options.allowedPackages });
2532
+ if (!next.loaded) {
2533
+ throw new PulseProjectError(
2534
+ 'PULSE_JAVASCRIPT_APPLICATION_UNAVAILABLE',
2535
+ 'The graph-backed JavaScript application could not be loaded.',
2536
+ { planHash: next.plan.planHash, blockers: next.plan.blockers, automaticFallback: false }
2537
+ );
2538
+ }
2539
+ const nextCompiled = compileProject(project);
2540
+ prepared = next;
2541
+ application = next.loaded.application;
2542
+ schemaCodecs = createCanonicalSchemaCodecs(nextCompiled.schema.bundle.registry);
2543
+ compileError = undefined;
2544
+ const watchFiles = javascriptProjectWatchFiles(project, next, nextCompiled);
2545
+ syncWatchFiles(watchFiles);
2546
+ events(Object.freeze({
2547
+ event: reason === 'initial' ? 'compiled' : 'reloaded',
2548
+ target: 'javascript',
2549
+ targetId: descriptor.targetId,
2550
+ entry: relative(project.entryFile, project.root),
2551
+ planHash: next.plan.planHash,
2552
+ graphHash: next.plan.graph.graphHash,
2553
+ watchFiles: Object.freeze(watchFiles.map((file) => relative(file, project.root)))
2554
+ }));
2555
+ } catch (error) {
2556
+ if (!application) compileError = error;
2557
+ events(Object.freeze({ event: 'compile-error', target: 'javascript', retainedLastGoodProgram: Boolean(application), error: errorSummary(error, project.dev.secrets) }));
2558
+ }
2559
+ }
2560
+
2561
+ function scheduleReload() {
2562
+ if (reloadTimer) clearTimeout(reloadTimer);
2563
+ reloadTimer = setTimeout(() => { reloadTimer = undefined; reload('change'); }, 60);
2564
+ }
2565
+
2566
+ reload('initial');
2567
+ if (compileError) throw compileError;
2568
+
2569
+ let handled = 0;
2570
+ let server;
2571
+ const structuredBodyLimit = project.schemas.active
2572
+ ? Math.min(project.dev.maxBodyBytes, project.schemas.maxBytes)
2573
+ : project.dev.maxBodyBytes;
2574
+ server = javascript.createServer(null, {
2575
+ getApplication() {
2576
+ if (compileError) throw compileError;
2577
+ if (!application) throw new PulseProjectError('PULSE_JAVASCRIPT_APPLICATION_UNAVAILABLE', 'No last-good JavaScript application is available.');
2578
+ return application;
2579
+ },
2580
+ schemaCodecs() {
2581
+ if (compileError) throw compileError;
2582
+ return schemaCodecs;
2583
+ },
2584
+ strict: project.strict !== false,
2585
+ provider: project.provider,
2586
+ maxBodyBytes: structuredBodyLimit,
2587
+ application: Object.freeze({
2588
+ projectHash: project.projectHash,
2589
+ planHash: project.planHash,
2590
+ profile: project.profile,
2591
+ target: 'javascript',
2592
+ provider: project.provider
2593
+ }),
2594
+ capabilities: options.capabilities,
2595
+ config: project.dev.config,
2596
+ secrets: project.dev.secrets,
2597
+ kv: project.dev.kv,
2598
+ fetchImplementation: javascript.createFixtureFetch(
2599
+ project.dev.fetches,
2600
+ project.dev.networkFetch ? globalThis.fetch : undefined
2601
+ ),
2602
+ maxRequestBodyBytes: structuredBodyLimit,
2603
+ maxFetchBodyBytes: structuredBodyLimit,
2604
+ onRequest(event) {
2605
+ handled += 1;
2606
+ events(Object.freeze({ event: 'request', target: 'javascript', ...event, requestId: `dev:${handled}` }));
2607
+ if (options.once) server.close();
2608
+ },
2609
+ onError(error, context) {
2610
+ const request = context && context.request;
2611
+ events(Object.freeze({
2612
+ event: 'request-error',
2613
+ target: 'javascript',
2614
+ method: request && request.method || 'GET',
2615
+ path: request && request.url || '/',
2616
+ error: errorSummary(error, project.dev.secrets)
2617
+ }));
2618
+ if (options.once) server.close();
2619
+ }
2620
+ });
2621
+
2622
+ function cleanup() {
2623
+ if (reloadTimer) clearTimeout(reloadTimer);
2624
+ for (const [file, listener] of watched) fs.unwatchFile(file, listener);
2625
+ watched.clear();
2626
+ }
2627
+ server.once('close', cleanup);
2628
+ server.once('error', cleanup);
2629
+ const listenHost = options.host || project.dev.host;
2630
+ const listenPort = options.port !== undefined ? Number(options.port) : project.dev.port;
2631
+ server.listen(listenPort, listenHost);
2632
+ await once(server, 'listening');
2633
+ const address = server.address();
2634
+ const boundHost = typeof address === 'object' && address ? address.address : listenHost;
2635
+ const boundPort = typeof address === 'object' && address ? address.port : listenPort;
2636
+ const advertisedHost = listenHost === '0.0.0.0' || listenHost === '::' ? '127.0.0.1' : listenHost;
2637
+ const urlHost = advertisedHost.includes(':') ? `[${advertisedHost}]` : advertisedHost;
2638
+ const ready = Object.freeze({
2639
+ event: 'ready',
2640
+ version: PROJECT_EXECUTION_VERSION,
2641
+ provider: project.provider,
2642
+ target: 'javascript',
2643
+ targetId: descriptor.targetId,
2644
+ runtimeClass: descriptor.runtimeClass,
2645
+ host: boundHost,
2646
+ port: boundPort,
2647
+ url: `http://${urlHost}:${boundPort}`,
2648
+ watch: watched.size > 0,
2649
+ watchFiles: Object.freeze([...watched.keys()].map((file) => relative(file, project.root))),
2650
+ once: Boolean(options.once),
2651
+ applicationPlan: Object.freeze({ planHash: prepared.plan.planHash, graphHash: prepared.plan.graph.graphHash }),
2652
+ automaticFallback: false,
2653
+ project: projectJson(project)
2654
+ });
2655
+ events(ready);
2656
+ return Object.freeze({ server, ready, closed: once(server, 'close') });
2657
+ }
2658
+
2659
+ async function startDevServer(project, options = {}) {
2660
+ if ((project.target || 'native') === 'javascript') return startJavascriptDevServer(project, options);
2661
+ const driver = assertExecutableProvider(project, 'dev');
2662
+ assertImplementedTarget(project, 'dev');
2663
+ const executeCanonicalProgram = driver.execute;
2664
+ let compiled;
2665
+ let program;
2666
+ let native;
2667
+ let exactNativeCrypto = false;
2668
+ let packageArtifacts = Object.freeze([]);
2669
+ let compileError;
2670
+ let reloadTimer;
2671
+ const watchEnabled = project.dev.watch && options.watch !== false;
2672
+ const watched = new Map();
2673
+ const events = typeof options.onEvent === 'function' ? options.onEvent : () => {};
2674
+ function syncWatchFiles(files) {
2675
+ if (!watchEnabled) return;
2676
+ const desired = new Set((files || []).map((file) => path.resolve(file)));
2677
+ for (const [file, listener] of watched) {
2678
+ if (desired.has(file)) continue;
2679
+ fs.unwatchFile(file, listener);
2680
+ watched.delete(file);
2681
+ }
2682
+ for (const file of desired) {
2683
+ if (watched.has(file)) continue;
2684
+ const listener = scheduleReload;
2685
+ fs.watchFile(file, { interval: 200 }, listener);
2686
+ watched.set(file, listener);
2687
+ }
2688
+ }
2689
+ function reload(reason) {
2690
+ try {
2691
+ const nextCompiled = compileProject(project);
2692
+ const nextExactNativeCrypto = requiresExactNativeCrypto(nextCompiled);
2693
+ const nextProgram = nextExactNativeCrypto ? null : loadCanonicalModule(nextCompiled);
2694
+ const nextNative = nextExactNativeCrypto
2695
+ ? compileNativeProjectInMemory(project, { ...options, compiled: nextCompiled }).native
2696
+ : null;
2697
+ compiled = nextCompiled;
2698
+ program = nextProgram;
2699
+ native = nextNative;
2700
+ exactNativeCrypto = nextExactNativeCrypto;
2701
+ packageArtifacts = packageRealizationArtifactsForCompiled(nextCompiled);
2702
+ compileError = undefined;
2703
+ syncWatchFiles(compiled.watchFiles);
2704
+ events(Object.freeze({
2705
+ event: reason === 'initial' ? 'compiled' : 'reloaded',
2706
+ entry: relative(project.entryFile, project.root),
2707
+ sourceHash: compiled.metadata.sourceHash,
2708
+ projectSourceHash: compiled.metadata.projectSourceHash,
2709
+ schemaSourceHash: compiled.metadata.schemaSourceHash,
2710
+ watchFiles: Object.freeze(compiled.watchFiles.map((file) => relative(file, project.root)))
2711
+ }));
2712
+ } catch (error) {
2713
+ if (!program) compileError = error;
2714
+ events(Object.freeze({ event: 'compile-error', retainedLastGoodProgram: Boolean(program), error: errorSummary(error, project.dev.secrets) }));
2715
+ }
2716
+ }
2717
+ function scheduleReload() {
2718
+ if (reloadTimer) clearTimeout(reloadTimer);
2719
+ reloadTimer = setTimeout(() => { reloadTimer = undefined; reload('change'); }, 60);
2720
+ }
2721
+ reload('initial');
2722
+ if (compileError) throw compileError;
2723
+
2724
+ let handled = 0;
2725
+ const server = http.createServer(async (req, res) => {
2726
+ if (options.once) res.once('finish', () => server.close());
2727
+ try {
2728
+ if (compileError) throw compileError;
2729
+ const bodyLimit = project.schemas.active ? Math.min(project.dev.maxBodyBytes, project.schemas.maxBytes) : project.dev.maxBodyBytes;
2730
+ const body = await readRequestBody(req, bodyLimit);
2731
+ const host = req.headers.host || `${project.dev.host}:${project.dev.port}`;
2732
+ const url = new URL(req.url || '/', `http://${host}`);
2733
+ const executionOptions = providerExecutionOptions(project, {
2734
+ packageArtifacts,
2735
+ request: { method: req.method || 'GET', url: url.href, path: url.pathname, headers: requestHeaders(req), body: body || undefined },
2736
+ config: project.dev.config,
2737
+ secrets: project.dev.secrets,
2738
+ kv: project.dev.kv,
2739
+ fetches: project.dev.fetches,
2740
+ maxBodyBytes: bodyLimit,
2741
+ fetchImplementation: project.dev.networkFetch ? globalThis.fetch : undefined,
2742
+ liveFetch: project.dev.networkFetch,
2743
+ executionId: `dev:${++handled}`
2744
+ });
2745
+ const execution = exactNativeCrypto
2746
+ ? await executeCanonicalNativeModule(native, executionOptions)
2747
+ : await executeCanonicalProgram(program, executionOptions);
2748
+ writeNodeHttpResponse(res, execution.response);
2749
+ events(Object.freeze({ event: 'request', method: req.method || 'GET', path: url.pathname, status: execution.response.status, effects: execution.effectCount }));
2750
+ } catch (error) {
2751
+ devErrorResponse(res, error, project.dev.secrets);
2752
+ events(Object.freeze({ event: 'request-error', method: req.method || 'GET', path: req.url || '/', error: errorSummary(error, project.dev.secrets) }));
2753
+ }
2754
+ });
2755
+
2756
+ function cleanup() {
2757
+ if (reloadTimer) clearTimeout(reloadTimer);
2758
+ for (const [file, listener] of watched) fs.unwatchFile(file, listener);
2759
+ watched.clear();
2760
+ }
2761
+ server.once('close', cleanup);
2762
+ server.once('error', cleanup);
2763
+ const listenHost = options.host || project.dev.host;
2764
+ const listenPort = options.port !== undefined ? Number(options.port) : project.dev.port;
2765
+ server.listen(listenPort, listenHost);
2766
+ await once(server, 'listening');
2767
+ const address = server.address();
2768
+ const boundHost = typeof address === 'object' && address ? address.address : listenHost;
2769
+ const boundPort = typeof address === 'object' && address ? address.port : listenPort;
2770
+ const advertisedHost = listenHost === '0.0.0.0' || listenHost === '::' ? '127.0.0.1' : listenHost;
2771
+ const urlHost = advertisedHost.includes(':') ? `[${advertisedHost}]` : advertisedHost;
2772
+ const ready = Object.freeze({
2773
+ event: 'ready',
2774
+ version: PROJECT_EXECUTION_VERSION,
2775
+ provider: project.provider,
2776
+ host: boundHost,
2777
+ port: boundPort,
2778
+ url: `http://${urlHost}:${boundPort}`,
2779
+ watch: watched.size > 0,
2780
+ watchFiles: Object.freeze([...watched.keys()].map((file) => relative(file, project.root))),
2781
+ once: Boolean(options.once),
2782
+ project: projectJson(project)
2783
+ });
2784
+ events(ready);
2785
+ return Object.freeze({ server, ready, closed: once(server, 'close') });
2786
+ }
2787
+
2788
+ function initProject(target, options = {}) {
2789
+ const root = path.resolve(target || '.');
2790
+ if (fs.existsSync(root)) {
2791
+ const entries = fs.readdirSync(root);
2792
+ if (entries.length > 0 && !options.force) throw new PulseProjectError('PULSE_INIT_NOT_EMPTY', `Target directory is not empty: ${root}`, { root, hint: 'Use --force only when replacing the generated Pulse files is intentional.' });
2793
+ }
2794
+
2795
+ const normalizedName = String(options.name || path.basename(root) || 'pulse-app').toLowerCase().replace(/[^a-z0-9._-]+/g, '-').replace(/^-+|-+$/g, '');
2796
+ const name = normalizedName || 'pulse-app';
2797
+ const provider = String(options.provider || 'node').toLowerCase();
2798
+ let driver;
2799
+ try {
2800
+ driver = getProviderDriver(provider);
2801
+ } catch (_) {
2802
+ throw new PulseProjectError(
2803
+ 'PULSE_INIT_PROVIDER_UNSUPPORTED',
2804
+ 'pulse init requires a registered executable provider template.',
2805
+ { provider, supported: providerIds({ executable: true }) }
2806
+ );
2807
+ }
2808
+ if (!driver.executable || typeof driver.initTemplate !== 'function') {
2809
+ throw new PulseProjectError(
2810
+ 'PULSE_INIT_PROVIDER_UNSUPPORTED',
2811
+ 'pulse init requires a registered executable provider template.',
2812
+ { provider, supported: providerIds({ executable: true }) }
2813
+ );
2814
+ }
2815
+ const template = driver.initTemplate(name);
2816
+ const profileFragments = ` outDir: 'dist',
2817
+ dev: { host: '127.0.0.1', port: 8787 },
2818
+ ${template.profileFragment || ''}`;
2819
+
2820
+ const dependencies = { '@pulse-compute/pulse': cliPackageVersion };
2821
+ Object.assign(dependencies, template.dependencies || {});
2822
+
2823
+ const files = {
2824
+ '.gitignore': 'dist\nnode_modules\n',
2825
+ '.pulse/.gitignore': '*\n!.gitignore\n!config.ts\n',
2826
+ '.pulse/config.ts': `import { defineConfig } from '@pulse-compute/pulse';
2827
+
2828
+ export default defineConfig((_scope) => ({
2829
+ pulse: {
2830
+ entry: 'src/index.ts',
2831
+ tests: 'tests/pulse.harness.ts',
2832
+ defaultProfile: 'local',
2833
+ strict: true,
2834
+ },
2835
+ local: {
2836
+ host: '${provider}',
2837
+ target: 'native',
2838
+ ${profileFragments}
2839
+ },
2840
+ }));
2841
+ `,
2842
+ 'README.md': `# ${name}\n\nInstall dependencies with \`npm install\`, then run \`npm run doctor\`.\n\nThe generated project uses the conventional \`.pulse/config.ts\` workspace, an async \`Pulse\` application root, and a dedicated test harness.\n\nUse \`npm run dev\`, \`npm test\`, \`npm run inspect\`, \`npm run compile\`, and \`npm run build\` for the canonical project workflow.\n`,
2843
+ 'package.json': stableJson({
2844
+ name,
2845
+ version: '0.0.0',
2846
+ private: true,
2847
+ scripts: {
2848
+ build: 'pulse build',
2849
+ compile: 'pulse compile',
2850
+ dev: 'pulse dev',
2851
+ doctor: 'pulse doctor',
2852
+ inspect: 'pulse inspect',
2853
+ test: 'pulse test'
2854
+ },
2855
+ dependencies,
2856
+ devDependencies: { '@pulse-compute/cli': cliPackageVersion, typescript: '5.9.3' }
2857
+ }),
2858
+ 'src/index.ts': `import { Pulse } from '@pulse-compute/pulse';
2859
+
2860
+ const app = new Pulse({ auto: true });
2861
+
2862
+ app.get('/health', async (ctx) => {
2863
+ return ctx.json({ ok: true });
2864
+ });
2865
+
2866
+ app.get('/', async (ctx) => {
2867
+ return ctx.text('Pulse is running');
2868
+ });
2869
+
2870
+ export default app;
2871
+ `,
2872
+ 'tests/pulse.harness.ts': `export default {
2873
+ cases: [
2874
+ {
2875
+ name: 'health',
2876
+ request: { method: 'GET', path: '/health' },
2877
+ expect: { status: 200, json: { ok: true } },
2878
+ },
2879
+ ],
2880
+ };
2881
+ `,
2882
+ 'tsconfig.json': stableJson({
2883
+ compilerOptions: {
2884
+ target: 'ES2022',
2885
+ module: 'NodeNext',
2886
+ moduleResolution: 'NodeNext',
2887
+ strict: true,
2888
+ noEmit: true,
2889
+ skipLibCheck: false
2890
+ },
2891
+ include: ['src/**/*.ts', '.pulse/**/*.ts', 'tests/**/*.ts']
2892
+ })
2893
+ };
2894
+
2895
+ const fileNames = Object.keys(files).sort();
2896
+ for (const name of fileNames) {
2897
+ const file = path.join(root, name);
2898
+ fs.mkdirSync(path.dirname(file), { recursive: true });
2899
+ if (fs.existsSync(file) && !options.force) throw new PulseProjectError('PULSE_INIT_FILE_EXISTS', `Refusing to overwrite ${file}.`, { file });
2900
+ fs.writeFileSync(file, files[name]);
2901
+ }
2902
+
2903
+ return Object.freeze({
2904
+ status: 'initialized',
2905
+ version: PROJECT_EXECUTION_VERSION,
2906
+ root,
2907
+ files: Object.freeze(fileNames),
2908
+ packageManager: 'npm',
2909
+ nextSteps: Object.freeze([`cd ${root}`, 'npm install', 'npm run doctor'])
2910
+ });
2911
+ }
2912
+
2913
+ module.exports = {
2914
+ PROJECT_EXECUTION_VERSION,
2915
+ BUILD_MANIFEST,
2916
+ COMPILE_MANIFEST,
2917
+ resolveOutputDirectory,
2918
+ compileProject,
2919
+ compileNativeProjectInMemory,
2920
+ prepareJavascriptApplication,
2921
+ compileNativeProject,
2922
+ buildProject,
2923
+ runProjectTests,
2924
+ inspectProject,
2925
+ doctorProject,
2926
+ startDevServer,
2927
+ initProject,
2928
+ errorSummary,
2929
+ responseJson
2930
+ };