agentskeptic 1.0.4 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -17
- package/config/marketing.json +186 -0
- package/dist/actionableFailure.d.ts.map +1 -1
- package/dist/actionableFailure.js +80 -0
- package/dist/actionableFailure.js.map +1 -1
- package/dist/assurance/buildAssuranceOutput.d.ts +29 -0
- package/dist/assurance/buildAssuranceOutput.d.ts.map +1 -0
- package/dist/assurance/buildAssuranceOutput.js +53 -0
- package/dist/assurance/buildAssuranceOutput.js.map +1 -0
- package/dist/assurance/checkStale.d.ts +7 -0
- package/dist/assurance/checkStale.d.ts.map +1 -1
- package/dist/assurance/checkStale.js +14 -3
- package/dist/assurance/checkStale.js.map +1 -1
- package/dist/assurance/runAssurance.d.ts.map +1 -1
- package/dist/assurance/runAssurance.js +26 -3
- package/dist/assurance/runAssurance.js.map +1 -1
- package/dist/bootstrap/executeBootstrapPack.d.ts.map +1 -1
- package/dist/bootstrap/executeBootstrapPack.js +3 -2
- package/dist/bootstrap/executeBootstrapPack.js.map +1 -1
- package/dist/cli/lockOrchestration.js +1 -1
- package/dist/cli/runFunnelAnonSet.js +1 -1
- package/dist/cli.js +37 -5
- package/dist/cli.js.map +1 -1
- package/dist/cliArgv.d.ts.map +1 -1
- package/dist/cliArgv.js +4 -2
- package/dist/cliArgv.js.map +1 -1
- package/dist/cliOperationalCodes.d.ts +1 -0
- package/dist/cliOperationalCodes.d.ts.map +1 -1
- package/dist/cliOperationalCodes.js +1 -0
- package/dist/cliOperationalCodes.js.map +1 -1
- package/dist/commercial/licensePreflight.d.ts.map +1 -1
- package/dist/commercial/licensePreflight.js.map +1 -1
- package/dist/commercial/verifyWorkloadClassify.d.ts +2 -7
- package/dist/commercial/verifyWorkloadClassify.d.ts.map +1 -1
- package/dist/commercial/verifyWorkloadClassify.js +1 -1
- package/dist/commercial/verifyWorkloadClassify.js.map +1 -1
- package/dist/commercial/verifyWorkloadClassify.test.js +7 -0
- package/dist/commercial/verifyWorkloadClassify.test.js.map +1 -1
- package/dist/crossing/crossingDecisionReadyFooter.d.ts +1 -1
- package/dist/crossing/crossingDecisionReadyFooter.d.ts.map +1 -1
- package/dist/crossing/crossingDecisionReadyFooter.js +1 -1
- package/dist/crossing/crossingDecisionReadyFooter.js.map +1 -1
- package/dist/debug-ui/app.css +42 -0
- package/dist/debug-ui/app.js +202 -12
- package/dist/debug-ui/index.html +11 -4
- package/dist/debug-ui/urlState.d.ts +15 -0
- package/dist/debug-ui/urlState.js +92 -0
- package/dist/debugCorpus.test.js +33 -7
- package/dist/debugCorpus.test.js.map +1 -1
- package/dist/debugServer.js +1 -1
- package/dist/debugServer.js.map +1 -1
- package/dist/debugServer.test.js +12 -6
- package/dist/debugServer.test.js.map +1 -1
- package/dist/debugUiUrlState.test.d.ts +2 -0
- package/dist/debugUiUrlState.test.d.ts.map +1 -0
- package/dist/debugUiUrlState.test.js +49 -0
- package/dist/debugUiUrlState.test.js.map +1 -0
- package/dist/decisionGate.d.ts.map +1 -1
- package/dist/decisionGate.js +2 -5
- package/dist/decisionGate.js.map +1 -1
- package/dist/discovery-payload-v1.json +23 -27
- package/dist/failureOriginCatalog.d.ts.map +1 -1
- package/dist/failureOriginCatalog.js +16 -0
- package/dist/failureOriginCatalog.js.map +1 -1
- package/dist/firstFiveMinutesChecklist.d.ts +11 -0
- package/dist/firstFiveMinutesChecklist.d.ts.map +1 -0
- package/dist/firstFiveMinutesChecklist.js +18 -0
- package/dist/firstFiveMinutesChecklist.js.map +1 -0
- package/dist/funnel/workflowLineageClassify.d.ts +1 -1
- package/dist/funnel/workflowLineageClassify.js +1 -1
- package/dist/langGraphCheckpointTrustGate.d.ts.map +1 -1
- package/dist/langGraphCheckpointTrustGate.js +2 -5
- package/dist/langGraphCheckpointTrustGate.js.map +1 -1
- package/dist/operationalDisposition.d.ts +8 -0
- package/dist/operationalDisposition.d.ts.map +1 -1
- package/dist/operationalDisposition.js +8 -0
- package/dist/operationalDisposition.js.map +1 -1
- package/dist/pipeline.d.ts +1 -0
- package/dist/pipeline.d.ts.map +1 -1
- package/dist/pipeline.js +18 -18
- package/dist/pipeline.js.map +1 -1
- package/dist/publicDistribution.generated.d.ts +2 -2
- package/dist/publicDistribution.generated.d.ts.map +1 -1
- package/dist/publicDistribution.generated.js +7 -8
- package/dist/publicDistribution.generated.js.map +1 -1
- package/dist/quickVerify/runQuickVerify.js +1 -1
- package/dist/quickVerify/runQuickVerify.js.map +1 -1
- package/dist/quickVerify/verifyExecution.d.ts +1 -1
- package/dist/quickVerify/verifyExecution.d.ts.map +1 -1
- package/dist/quickVerify/verifyExecution.js +3 -2
- package/dist/quickVerify/verifyExecution.js.map +1 -1
- package/dist/reconciler.d.ts +6 -2
- package/dist/reconciler.d.ts.map +1 -1
- package/dist/reconciler.js +17 -11
- package/dist/reconciler.js.map +1 -1
- package/dist/registryDraft/createRegistryDraftAjv.d.ts +1 -1
- package/dist/registryDraft/createRegistryDraftAjv.js +1 -1
- package/dist/relationalInvariant.d.ts +13 -3
- package/dist/relationalInvariant.d.ts.map +1 -1
- package/dist/relationalInvariant.existsSql.test.js +1 -1
- package/dist/relationalInvariant.existsSql.test.js.map +1 -1
- package/dist/relationalInvariant.js +59 -39
- package/dist/relationalInvariant.js.map +1 -1
- package/dist/relationalInvariant.test.js +2 -2
- package/dist/relationalInvariant.test.js.map +1 -1
- package/dist/resolveExpectation.d.ts +18 -2
- package/dist/resolveExpectation.d.ts.map +1 -1
- package/dist/resolveExpectation.js +332 -1
- package/dist/resolveExpectation.js.map +1 -1
- package/dist/resolveExpectation.test.js +25 -0
- package/dist/resolveExpectation.test.js.map +1 -1
- package/dist/runComparison.d.ts.map +1 -1
- package/dist/runComparison.js +18 -3
- package/dist/runComparison.js.map +1 -1
- package/dist/schema-validation.test.js +29 -0
- package/dist/schema-validation.test.js.map +1 -1
- package/dist/schemaLoad.d.ts +1 -1
- package/dist/schemaLoad.d.ts.map +1 -1
- package/dist/schemaLoad.js +2 -0
- package/dist/schemaLoad.js.map +1 -1
- package/dist/sqlDialect.d.ts +8 -0
- package/dist/sqlDialect.d.ts.map +1 -0
- package/dist/sqlDialect.js +37 -0
- package/dist/sqlDialect.js.map +1 -0
- package/dist/stateWitness.d.ts +4 -0
- package/dist/stateWitness.d.ts.map +1 -0
- package/dist/stateWitness.js +383 -0
- package/dist/stateWitness.js.map +1 -0
- package/dist/stateWitness.test.d.ts +2 -0
- package/dist/stateWitness.test.d.ts.map +1 -0
- package/dist/stateWitness.test.js +120 -0
- package/dist/stateWitness.test.js.map +1 -0
- package/dist/telemetry/ossClaimOrigin.d.ts +1 -1
- package/dist/telemetry/ossClaimOrigin.js +1 -1
- package/dist/telemetry/verificationHypothesisContract.d.ts +1 -1
- package/dist/telemetry/verificationHypothesisContract.js +1 -1
- package/dist/types.d.ts +105 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/verificationConnections.d.ts +10 -0
- package/dist/verificationConnections.d.ts.map +1 -0
- package/dist/verificationConnections.js +190 -0
- package/dist/verificationConnections.js.map +1 -0
- package/dist/verificationDatabaseUrl.d.ts +11 -0
- package/dist/verificationDatabaseUrl.d.ts.map +1 -0
- package/dist/verificationDatabaseUrl.js +41 -0
- package/dist/verificationDatabaseUrl.js.map +1 -0
- package/dist/verificationDatabaseUrl.test.d.ts +2 -0
- package/dist/verificationDatabaseUrl.test.d.ts.map +1 -0
- package/dist/verificationDatabaseUrl.test.js +66 -0
- package/dist/verificationDatabaseUrl.test.js.map +1 -0
- package/dist/verificationDiagnostics.d.ts.map +1 -1
- package/dist/verificationDiagnostics.js +29 -8
- package/dist/verificationDiagnostics.js.map +1 -1
- package/dist/verificationDiagnostics.test.js +15 -0
- package/dist/verificationDiagnostics.test.js.map +1 -1
- package/dist/verificationPolicy.d.ts +2 -1
- package/dist/verificationPolicy.d.ts.map +1 -1
- package/dist/verificationPolicy.js +84 -0
- package/dist/verificationPolicy.js.map +1 -1
- package/dist/verificationPolicy.test.js +7 -0
- package/dist/verificationPolicy.test.js.map +1 -1
- package/dist/verificationUserPhrases.d.ts.map +1 -1
- package/dist/verificationUserPhrases.js +18 -0
- package/dist/verificationUserPhrases.js.map +1 -1
- package/dist/vitestMonorepoRoot.d.ts +10 -0
- package/dist/vitestMonorepoRoot.d.ts.map +1 -0
- package/dist/vitestMonorepoRoot.js +97 -0
- package/dist/vitestMonorepoRoot.js.map +1 -0
- package/dist/wireReasonCodes.d.ts +18 -0
- package/dist/wireReasonCodes.d.ts.map +1 -1
- package/dist/wireReasonCodes.js +18 -0
- package/dist/wireReasonCodes.js.map +1 -1
- package/package.json +29 -34
- package/schemas/assurance-output-v1.schema.json +81 -0
- package/schemas/openapi-commercial-v1.in.yaml +36 -3
- package/schemas/openapi-commercial-v1.yaml +37 -4
- package/schemas/tools-registry.schema.json +103 -0
- package/schemas/workflow-engine-result.schema.json +69 -1
- package/schemas/workflow-truth-report.schema.json +12 -0
- package/scripts/discovery-acquisition.lib.cjs +6 -17
- package/scripts/discovery-payload.lib.cjs +5 -3
- package/scripts/emit-primary-marketing.cjs +326 -0
- package/scripts/origin.cjs +52 -0
- package/scripts/public-product-anchors.cjs +3 -0
- package/scripts/validate-marketing.cjs +156 -0
|
@@ -72,12 +72,115 @@
|
|
|
72
72
|
"items": { "$ref": "#/$defs/sqlRelationalCheck" }
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"type": "object",
|
|
78
|
+
"additionalProperties": false,
|
|
79
|
+
"required": ["kind", "provider", "documentId", "indexName"],
|
|
80
|
+
"properties": {
|
|
81
|
+
"kind": { "const": "vector_document" },
|
|
82
|
+
"provider": { "type": "string", "enum": ["pinecone", "weaviate", "chroma"] },
|
|
83
|
+
"documentId": { "$ref": "#/$defs/stringSpec" },
|
|
84
|
+
"indexName": { "$ref": "#/$defs/stringSpec" },
|
|
85
|
+
"namespace": { "$ref": "#/$defs/stringSpec" },
|
|
86
|
+
"host": { "$ref": "#/$defs/stringSpec" },
|
|
87
|
+
"metadataEq": { "$ref": "#/$defs/requiredFieldsPointer" },
|
|
88
|
+
"expectPayloadSha256": { "$ref": "#/$defs/stringSpec" }
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"type": "object",
|
|
93
|
+
"additionalProperties": false,
|
|
94
|
+
"required": ["kind", "bucket", "key"],
|
|
95
|
+
"properties": {
|
|
96
|
+
"kind": { "const": "object_storage_object" },
|
|
97
|
+
"bucket": { "$ref": "#/$defs/stringSpec" },
|
|
98
|
+
"key": { "$ref": "#/$defs/stringSpec" },
|
|
99
|
+
"endpoint": { "$ref": "#/$defs/stringSpec" },
|
|
100
|
+
"expectSizeBytes": { "$ref": "#/$defs/numberOrPointerSpec" },
|
|
101
|
+
"expectSha256": { "$ref": "#/$defs/stringSpec" },
|
|
102
|
+
"expectEtag": { "$ref": "#/$defs/stringSpec" }
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"type": "object",
|
|
107
|
+
"additionalProperties": false,
|
|
108
|
+
"required": ["kind", "url"],
|
|
109
|
+
"properties": {
|
|
110
|
+
"kind": { "const": "http_witness" },
|
|
111
|
+
"method": { "type": "string", "enum": ["GET", "POST"] },
|
|
112
|
+
"url": { "$ref": "#/$defs/stringSpec" },
|
|
113
|
+
"expectedStatus": { "$ref": "#/$defs/numberOrPointerSpec" },
|
|
114
|
+
"assertions": {
|
|
115
|
+
"type": "array",
|
|
116
|
+
"items": { "$ref": "#/$defs/httpWitnessAssertion" }
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"type": "object",
|
|
122
|
+
"additionalProperties": false,
|
|
123
|
+
"required": ["kind", "collection", "filterPointer", "requiredFields"],
|
|
124
|
+
"properties": {
|
|
125
|
+
"kind": { "const": "mongo_document" },
|
|
126
|
+
"collection": { "$ref": "#/$defs/stringSpec" },
|
|
127
|
+
"filterPointer": {
|
|
128
|
+
"type": "object",
|
|
129
|
+
"additionalProperties": false,
|
|
130
|
+
"required": ["pointer"],
|
|
131
|
+
"properties": {
|
|
132
|
+
"pointer": { "type": "string", "pattern": "^/" }
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
"requiredFields": { "$ref": "#/$defs/requiredFieldsPointer" }
|
|
136
|
+
}
|
|
75
137
|
}
|
|
76
138
|
]
|
|
77
139
|
}
|
|
78
140
|
}
|
|
79
141
|
},
|
|
80
142
|
"$defs": {
|
|
143
|
+
"stringSpec": {
|
|
144
|
+
"oneOf": [
|
|
145
|
+
{
|
|
146
|
+
"type": "object",
|
|
147
|
+
"additionalProperties": false,
|
|
148
|
+
"required": ["const"],
|
|
149
|
+
"properties": { "const": { "type": "string", "minLength": 1 } }
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"type": "object",
|
|
153
|
+
"additionalProperties": false,
|
|
154
|
+
"required": ["pointer"],
|
|
155
|
+
"properties": { "pointer": { "type": "string", "pattern": "^/" } }
|
|
156
|
+
}
|
|
157
|
+
]
|
|
158
|
+
},
|
|
159
|
+
"numberOrPointerSpec": {
|
|
160
|
+
"oneOf": [
|
|
161
|
+
{
|
|
162
|
+
"type": "object",
|
|
163
|
+
"additionalProperties": false,
|
|
164
|
+
"required": ["const"],
|
|
165
|
+
"properties": { "const": { "type": "number" } }
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
"type": "object",
|
|
169
|
+
"additionalProperties": false,
|
|
170
|
+
"required": ["pointer"],
|
|
171
|
+
"properties": { "pointer": { "type": "string", "pattern": "^/" } }
|
|
172
|
+
}
|
|
173
|
+
]
|
|
174
|
+
},
|
|
175
|
+
"httpWitnessAssertion": {
|
|
176
|
+
"type": "object",
|
|
177
|
+
"additionalProperties": false,
|
|
178
|
+
"required": ["jsonPointer", "value"],
|
|
179
|
+
"properties": {
|
|
180
|
+
"jsonPointer": { "type": "string", "minLength": 1 },
|
|
181
|
+
"value": { "$ref": "#/$defs/scalarOrPointer" }
|
|
182
|
+
}
|
|
183
|
+
},
|
|
81
184
|
"tableSpec": {
|
|
82
185
|
"oneOf": [
|
|
83
186
|
{
|
|
@@ -414,6 +414,70 @@
|
|
|
414
414
|
}
|
|
415
415
|
}
|
|
416
416
|
},
|
|
417
|
+
"verificationRequestVectorDocument": {
|
|
418
|
+
"type": "object",
|
|
419
|
+
"additionalProperties": false,
|
|
420
|
+
"required": ["kind", "provider", "documentId", "indexName"],
|
|
421
|
+
"properties": {
|
|
422
|
+
"kind": { "const": "vector_document" },
|
|
423
|
+
"provider": { "type": "string", "enum": ["pinecone", "weaviate", "chroma"] },
|
|
424
|
+
"documentId": { "type": "string", "minLength": 1 },
|
|
425
|
+
"indexName": { "type": "string", "minLength": 1 },
|
|
426
|
+
"namespace": { "type": "string" },
|
|
427
|
+
"host": { "type": "string", "minLength": 1 },
|
|
428
|
+
"metadataSubset": { "type": "object", "additionalProperties": true },
|
|
429
|
+
"expectPayloadSha256": { "type": "string", "minLength": 1 }
|
|
430
|
+
}
|
|
431
|
+
},
|
|
432
|
+
"verificationRequestObjectStorageObject": {
|
|
433
|
+
"type": "object",
|
|
434
|
+
"additionalProperties": false,
|
|
435
|
+
"required": ["kind", "bucket", "key"],
|
|
436
|
+
"properties": {
|
|
437
|
+
"kind": { "const": "object_storage_object" },
|
|
438
|
+
"bucket": { "type": "string", "minLength": 1 },
|
|
439
|
+
"key": { "type": "string", "minLength": 1 },
|
|
440
|
+
"endpoint": { "type": "string", "minLength": 1 },
|
|
441
|
+
"expectSizeBytes": { "type": "number", "minimum": 0 },
|
|
442
|
+
"expectSha256": { "type": "string", "minLength": 1 },
|
|
443
|
+
"expectEtag": { "type": "string", "minLength": 1 }
|
|
444
|
+
}
|
|
445
|
+
},
|
|
446
|
+
"httpWitnessResolvedAssertion": {
|
|
447
|
+
"type": "object",
|
|
448
|
+
"additionalProperties": false,
|
|
449
|
+
"required": ["jsonPointer", "value"],
|
|
450
|
+
"properties": {
|
|
451
|
+
"jsonPointer": { "type": "string", "minLength": 1 },
|
|
452
|
+
"value": { "type": ["string", "number", "boolean", "null"] }
|
|
453
|
+
}
|
|
454
|
+
},
|
|
455
|
+
"verificationRequestHttpWitness": {
|
|
456
|
+
"type": "object",
|
|
457
|
+
"additionalProperties": false,
|
|
458
|
+
"required": ["kind", "method", "url"],
|
|
459
|
+
"properties": {
|
|
460
|
+
"kind": { "const": "http_witness" },
|
|
461
|
+
"method": { "type": "string", "enum": ["GET", "POST"] },
|
|
462
|
+
"url": { "type": "string", "minLength": 1 },
|
|
463
|
+
"expectedStatus": { "type": "integer", "minimum": 100, "maximum": 599 },
|
|
464
|
+
"assertions": {
|
|
465
|
+
"type": "array",
|
|
466
|
+
"items": { "$ref": "#/$defs/httpWitnessResolvedAssertion" }
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
},
|
|
470
|
+
"verificationRequestMongoDocument": {
|
|
471
|
+
"type": "object",
|
|
472
|
+
"additionalProperties": false,
|
|
473
|
+
"required": ["kind", "collection", "filter", "requiredFields"],
|
|
474
|
+
"properties": {
|
|
475
|
+
"kind": { "const": "mongo_document" },
|
|
476
|
+
"collection": { "type": "string", "minLength": 1 },
|
|
477
|
+
"filter": { "type": "object", "additionalProperties": true },
|
|
478
|
+
"requiredFields": { "$ref": "#/$defs/requiredFieldsMap" }
|
|
479
|
+
}
|
|
480
|
+
},
|
|
417
481
|
"effectOutcome": {
|
|
418
482
|
"type": "object",
|
|
419
483
|
"additionalProperties": false,
|
|
@@ -478,7 +542,11 @@
|
|
|
478
542
|
{ "$ref": "#/$defs/verificationRequestSqlRow" },
|
|
479
543
|
{ "$ref": "#/$defs/verificationRequestSqlRowAbsent" },
|
|
480
544
|
{ "$ref": "#/$defs/verificationRequestSqlEffects" },
|
|
481
|
-
{ "$ref": "#/$defs/verificationRequestSqlRelational" }
|
|
545
|
+
{ "$ref": "#/$defs/verificationRequestSqlRelational" },
|
|
546
|
+
{ "$ref": "#/$defs/verificationRequestVectorDocument" },
|
|
547
|
+
{ "$ref": "#/$defs/verificationRequestObjectStorageObject" },
|
|
548
|
+
{ "$ref": "#/$defs/verificationRequestHttpWitness" },
|
|
549
|
+
{ "$ref": "#/$defs/verificationRequestMongoDocument" }
|
|
482
550
|
]
|
|
483
551
|
},
|
|
484
552
|
"status": {
|
|
@@ -624,6 +624,18 @@
|
|
|
624
624
|
},
|
|
625
625
|
{
|
|
626
626
|
"$ref": "https://agentskeptic.com/schemas/workflow-engine-result.schema.json#/$defs/verificationRequestSqlRelational"
|
|
627
|
+
},
|
|
628
|
+
{
|
|
629
|
+
"$ref": "https://agentskeptic.com/schemas/workflow-engine-result.schema.json#/$defs/verificationRequestVectorDocument"
|
|
630
|
+
},
|
|
631
|
+
{
|
|
632
|
+
"$ref": "https://agentskeptic.com/schemas/workflow-engine-result.schema.json#/$defs/verificationRequestObjectStorageObject"
|
|
633
|
+
},
|
|
634
|
+
{
|
|
635
|
+
"$ref": "https://agentskeptic.com/schemas/workflow-engine-result.schema.json#/$defs/verificationRequestHttpWitness"
|
|
636
|
+
},
|
|
637
|
+
{
|
|
638
|
+
"$ref": "https://agentskeptic.com/schemas/workflow-engine-result.schema.json#/$defs/verificationRequestMongoDocument"
|
|
627
639
|
}
|
|
628
640
|
]
|
|
629
641
|
}
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const { existsSync, readFileSync, readdirSync } = require("node:fs");
|
|
4
4
|
const { join } = require("node:path");
|
|
5
|
-
const Ajv = require("ajv");
|
|
6
|
-
const addFormats = require("ajv-formats");
|
|
7
5
|
|
|
8
6
|
const PLACEHOLDER_KEYS = [
|
|
9
7
|
["{{ORIGIN}}", "ORIGIN"],
|
|
@@ -20,8 +18,7 @@ const PLACEHOLDER_KEYS = [
|
|
|
20
18
|
*/
|
|
21
19
|
function discoveryPaths(root) {
|
|
22
20
|
return {
|
|
23
|
-
jsonPath: join(root, "config", "
|
|
24
|
-
schemaPath: join(root, "config", "discovery-acquisition.schema.json"),
|
|
21
|
+
jsonPath: join(root, "config", "marketing.json"),
|
|
25
22
|
};
|
|
26
23
|
}
|
|
27
24
|
|
|
@@ -177,20 +174,12 @@ function appendDiscoveryLlmsAppendix(baseLlms, discovery, canonicalOrigin) {
|
|
|
177
174
|
* @param {string} root
|
|
178
175
|
*/
|
|
179
176
|
function validateDiscoveryAcquisition(root) {
|
|
180
|
-
const { jsonPath
|
|
177
|
+
const { jsonPath } = discoveryPaths(root);
|
|
178
|
+
const { validateMarketing } = require("./validate-marketing.cjs");
|
|
179
|
+
validateMarketing(root);
|
|
181
180
|
const discovery = JSON.parse(readFileSync(jsonPath, "utf8"));
|
|
182
|
-
const
|
|
183
|
-
const
|
|
184
|
-
addFormats(ajv);
|
|
185
|
-
const validate = ajv.compile(schema);
|
|
186
|
-
if (!validate(discovery)) {
|
|
187
|
-
const msg = ajv.errorsText(validate.errors, { separator: "\n" });
|
|
188
|
-
throw new Error(`discovery-acquisition: schema validation failed:\n${msg}`);
|
|
189
|
-
}
|
|
190
|
-
const anchorsPath = join(root, "config", "public-product-anchors.json");
|
|
191
|
-
const anchors = JSON.parse(readFileSync(anchorsPath, "utf8"));
|
|
192
|
-
const { normalize } = require("./public-product-anchors.cjs");
|
|
193
|
-
const origin = normalize(anchors.productionCanonicalOrigin);
|
|
181
|
+
const { normalize } = require("./origin.cjs");
|
|
182
|
+
const origin = normalize(String(discovery.productionCanonicalOrigin));
|
|
194
183
|
buildDiscoveryFoldBody(discovery, origin);
|
|
195
184
|
const demo = discovery.shareableTerminalDemo;
|
|
196
185
|
if (demo && String(demo.transcript).includes("```")) {
|
|
@@ -132,8 +132,10 @@ function buildDiscoveryPayload(root) {
|
|
|
132
132
|
problemAnchor: padAnchor(path),
|
|
133
133
|
embedKey: embedKeyForExamplePath(path),
|
|
134
134
|
}));
|
|
135
|
-
const
|
|
136
|
-
|
|
135
|
+
const pm = /** @type {{ productionCanonicalOrigin: string; identityOneLiner: string; gitRepositoryUrl: string; npmPackageUrl: string }} */ (
|
|
136
|
+
discovery
|
|
137
|
+
);
|
|
138
|
+
const anchors = pm;
|
|
137
139
|
const canonicalOrigin = normalizeOrigin(anchors.productionCanonicalOrigin);
|
|
138
140
|
const integrateUrl = `${canonicalOrigin}/integrate`;
|
|
139
141
|
const learnHubUrl = `${canonicalOrigin}/guides`;
|
|
@@ -141,7 +143,7 @@ function buildDiscoveryPayload(root) {
|
|
|
141
143
|
const { owner, repo } = parseGithubRepoFromUrl(anchors.gitRepositoryUrl);
|
|
142
144
|
const llmsRaw = `https://raw.githubusercontent.com/${owner}/${repo}/refs/heads/${DISCOVERY_LLM_BRANCH}/llms.txt`;
|
|
143
145
|
const llmsBlob = `https://github.com/${owner}/${repo}/blob/${DISCOVERY_LLM_BRANCH}/llms.txt`;
|
|
144
|
-
const integratorVerificationSsotRaw = `https://raw.githubusercontent.com/${owner}/${repo}/refs/heads/${DISCOVERY_LLM_BRANCH}/docs/integrator-verification
|
|
146
|
+
const integratorVerificationSsotRaw = `https://raw.githubusercontent.com/${owner}/${repo}/refs/heads/${DISCOVERY_LLM_BRANCH}/docs/integrator-verification.md`;
|
|
145
147
|
const openapiRaw = `https://raw.githubusercontent.com/${owner}/${repo}/refs/heads/${DISCOVERY_LLM_BRANCH}/schemas/openapi-commercial-v1.yaml`;
|
|
146
148
|
const llms = /** @type {{ intentPhrases: string[]; notFor: string[]; relatedQueries: string[] }} */ (
|
|
147
149
|
discovery.llms
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { readFileSync, writeFileSync, mkdirSync } = require("node:fs");
|
|
4
|
+
const { join, dirname } = require("node:path");
|
|
5
|
+
const { normalize, assertNextPublicOriginParity, MARKETING_PATH } = require("./origin.cjs");
|
|
6
|
+
|
|
7
|
+
const ROOT = join(__dirname, "..");
|
|
8
|
+
|
|
9
|
+
const OPENAPI_IN = join(ROOT, "schemas", "openapi-commercial-v1.in.yaml");
|
|
10
|
+
const OPENAPI_OUT = join(ROOT, "schemas", "openapi-commercial-v1.yaml");
|
|
11
|
+
const OPENAPI_PUBLIC = join(ROOT, "website", "public", "openapi-commercial-v1.yaml");
|
|
12
|
+
const LLMS_PUBLIC = join(ROOT, "website", "public", "llms.txt");
|
|
13
|
+
const LLMS_REPO_ROOT = join(ROOT, "llms.txt");
|
|
14
|
+
const README_PATH = join(ROOT, "README.md");
|
|
15
|
+
const PKG_PATH = join(ROOT, "package.json");
|
|
16
|
+
|
|
17
|
+
const README_START = "<!-- public-product-anchors:start -->";
|
|
18
|
+
const README_END = "<!-- public-product-anchors:end -->";
|
|
19
|
+
const DISCOVERY_README_START = "<!-- discovery-acquisition-fold:start -->";
|
|
20
|
+
const DISCOVERY_README_END = "<!-- discovery-acquisition-fold:end -->";
|
|
21
|
+
const DISCOVERY_README_TITLE_START = "<!-- discovery-readme-title:start -->";
|
|
22
|
+
const DISCOVERY_README_TITLE_END = "<!-- discovery-readme-title:end -->";
|
|
23
|
+
|
|
24
|
+
const TOKENS = [
|
|
25
|
+
"__IDENTITY_ONE_LINER__",
|
|
26
|
+
"__DISTRIBUTION_CONTACT_URL__",
|
|
27
|
+
"__DISTRIBUTION_INTEGRATE_URL__",
|
|
28
|
+
"__DISTRIBUTION_REPO_URL__",
|
|
29
|
+
"__DISTRIBUTION_NPM_URL__",
|
|
30
|
+
"__OPENAPI_SELF_URL__",
|
|
31
|
+
"__SERVERS_ORIGIN__",
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @param {string} haystack
|
|
36
|
+
* @param {string} needle
|
|
37
|
+
*/
|
|
38
|
+
function countOccurrences(haystack, needle) {
|
|
39
|
+
let n = 0;
|
|
40
|
+
let i = 0;
|
|
41
|
+
while (true) {
|
|
42
|
+
const j = haystack.indexOf(needle, i);
|
|
43
|
+
if (j === -1) break;
|
|
44
|
+
n++;
|
|
45
|
+
i = j + needle.length;
|
|
46
|
+
}
|
|
47
|
+
return n;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function validateOpenapiTemplate() {
|
|
51
|
+
const template = readFileSync(OPENAPI_IN, "utf8");
|
|
52
|
+
for (const tok of TOKENS) {
|
|
53
|
+
const c = countOccurrences(template, tok);
|
|
54
|
+
if (c !== 1) {
|
|
55
|
+
throw new Error(`openapi template: token ${tok} must appear exactly once, found ${c}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function escapeYamlDoubleQuotedOneLiner(s) {
|
|
61
|
+
return String(s).replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @param {Record<string, unknown>} anchors
|
|
66
|
+
*/
|
|
67
|
+
function distributionSsotBlobUrl(anchors) {
|
|
68
|
+
const u = String(anchors.gitRepositoryUrl);
|
|
69
|
+
const m = u.match(/github\.com\/([^/]+)\/([^/#?]+)/i);
|
|
70
|
+
if (!m) throw new Error("emit-primary-marketing: cannot derive SSOT blob URL from gitRepositoryUrl");
|
|
71
|
+
const repo = m[2].replace(/\.git$/i, "");
|
|
72
|
+
return `https://github.com/${m[1]}/${repo}/blob/main/docs/public-distribution.md`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @param {string} line
|
|
77
|
+
* @param {string} origin
|
|
78
|
+
* @param {string} slug
|
|
79
|
+
*/
|
|
80
|
+
function expandCliFooterLine(line, origin, slug) {
|
|
81
|
+
const acquisitionUrl = `${origin}${slug}`;
|
|
82
|
+
const integrateUrl = `${origin}/integrate`;
|
|
83
|
+
let out = String(line)
|
|
84
|
+
.replace(/\{\{ORIGIN\}\}/g, origin)
|
|
85
|
+
.replace(/\{\{ACQUISITION_URL\}\}/g, acquisitionUrl)
|
|
86
|
+
.replace(/\{\{INTEGRATE_URL\}\}/g, integrateUrl);
|
|
87
|
+
if (out.includes("{{")) {
|
|
88
|
+
throw new Error(`emit-primary-marketing: unresolved placeholder in cliFollowupLines: ${line}`);
|
|
89
|
+
}
|
|
90
|
+
return out;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* @param {Record<string, unknown>} anchors
|
|
95
|
+
* @param {Record<string, unknown>} discovery
|
|
96
|
+
*/
|
|
97
|
+
function writePublicDistributionGenerated(anchors, discovery) {
|
|
98
|
+
const ssotUrl = distributionSsotBlobUrl(anchors);
|
|
99
|
+
const origin = normalize(anchors.productionCanonicalOrigin);
|
|
100
|
+
const slug = String(discovery.slug);
|
|
101
|
+
const cliLines = /** @type {string[]} */ (discovery.cliFollowupLines);
|
|
102
|
+
const expanded = cliLines.map((l) => expandCliFooterLine(l, origin, slug));
|
|
103
|
+
expanded.push(`Distribution contract (SSOT): ${ssotUrl}`);
|
|
104
|
+
if (expanded.length > 6) {
|
|
105
|
+
throw new Error(
|
|
106
|
+
`emit-primary-marketing: distribution footer exceeds 6 lines (${expanded.length}); shorten cliFollowupLines`,
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
const returnParts = expanded.map((line) => `${JSON.stringify(`${line}\n`)}`);
|
|
110
|
+
const pkgRaw = readFileSync(PKG_PATH, "utf8");
|
|
111
|
+
const pkgJson = JSON.parse(pkgRaw);
|
|
112
|
+
const cliSemver = String(pkgJson.version ?? "").trim();
|
|
113
|
+
if (!cliSemver) {
|
|
114
|
+
throw new Error("emit-primary-marketing: package.json missing version");
|
|
115
|
+
}
|
|
116
|
+
const body = `// Generated by npm run emit-primary-marketing — do not hand edit.
|
|
117
|
+
|
|
118
|
+
export const PUBLIC_DISTRIBUTION_SSOT_BLOB_URL = ${JSON.stringify(ssotUrl)};
|
|
119
|
+
|
|
120
|
+
export const PUBLIC_CANONICAL_SITE_ORIGIN = ${JSON.stringify(origin)};
|
|
121
|
+
|
|
122
|
+
export const AGENTSKEPTIC_CLI_SEMVER = ${JSON.stringify(cliSemver)};
|
|
123
|
+
|
|
124
|
+
export function formatDistributionFooter(): string {
|
|
125
|
+
return ${returnParts.join("\n + ")};
|
|
126
|
+
}
|
|
127
|
+
`;
|
|
128
|
+
writeFileSync(join(ROOT, "src", "publicDistribution.generated.ts"), body, "utf8");
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* @param {Record<string, unknown>} anchors
|
|
133
|
+
* @param {Record<string, unknown>} discovery
|
|
134
|
+
*/
|
|
135
|
+
function writeAgentsMd(anchors, discovery) {
|
|
136
|
+
const url = distributionSsotBlobUrl(anchors);
|
|
137
|
+
const origin = normalize(anchors.productionCanonicalOrigin);
|
|
138
|
+
const slug = String(discovery.slug);
|
|
139
|
+
const acquisitionUrl = `${origin}${slug}`;
|
|
140
|
+
const dp = require("./discovery-payload.lib.cjs");
|
|
141
|
+
const { owner, repo } = dp.parseGithubRepoFromUrl(String(anchors.gitRepositoryUrl));
|
|
142
|
+
const branch = dp.DISCOVERY_LLM_BRANCH;
|
|
143
|
+
const llmsRaw = `https://raw.githubusercontent.com/${owner}/${repo}/refs/heads/${branch}/llms.txt`;
|
|
144
|
+
const openapiRaw = `https://raw.githubusercontent.com/${owner}/${repo}/refs/heads/${branch}/schemas/openapi-commercial-v1.yaml`;
|
|
145
|
+
const body = `# AGENTS
|
|
146
|
+
|
|
147
|
+
Normative **public distribution** and anchor sync: [\`docs/public-distribution.md\`](docs/public-distribution.md) (same content as ${url}).
|
|
148
|
+
|
|
149
|
+
## Machine-readable product entrypoints
|
|
150
|
+
|
|
151
|
+
- Committed \`llms.txt\` at repo root (same bytes as site \`/llms.txt\` after prebuild sync).
|
|
152
|
+
- Raw GitHub \`llms.txt\`: ${llmsRaw}
|
|
153
|
+
- OpenAPI YAML (repo raw): ${openapiRaw}
|
|
154
|
+
- Acquisition page (canonical): ${acquisitionUrl}
|
|
155
|
+
`;
|
|
156
|
+
writeFileSync(join(ROOT, "AGENTS.md"), body, "utf8");
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function syncPrimaryMarketing() {
|
|
160
|
+
const discoveryLib = require("./discovery-acquisition.lib.cjs");
|
|
161
|
+
discoveryLib.validateDiscoveryAcquisition(ROOT);
|
|
162
|
+
const pm = discoveryLib.loadDiscoveryAcquisition(ROOT);
|
|
163
|
+
const anchors = pm;
|
|
164
|
+
const discovery = pm;
|
|
165
|
+
|
|
166
|
+
validateOpenapiTemplate();
|
|
167
|
+
|
|
168
|
+
const escaped = escapeYamlDoubleQuotedOneLiner(anchors.identityOneLiner);
|
|
169
|
+
const canonicalOrigin = normalize(anchors.productionCanonicalOrigin);
|
|
170
|
+
const openapiSelfCanonical = `${canonicalOrigin}/openapi-commercial-v1.yaml`;
|
|
171
|
+
|
|
172
|
+
const envUrl = process.env.NEXT_PUBLIC_APP_URL;
|
|
173
|
+
const effectivePublicOrigin =
|
|
174
|
+
typeof envUrl === "string" && envUrl.trim() ? envUrl.trim() : anchors.productionCanonicalOrigin;
|
|
175
|
+
const publicOriginNormalized = normalize(effectivePublicOrigin);
|
|
176
|
+
const openapiSelfEffective = `${publicOriginNormalized}/openapi-commercial-v1.yaml`;
|
|
177
|
+
|
|
178
|
+
const integrateUrl = `${canonicalOrigin}/integrate`;
|
|
179
|
+
|
|
180
|
+
const template = readFileSync(OPENAPI_IN, "utf8");
|
|
181
|
+
let mid = template;
|
|
182
|
+
mid = mid.replace("__IDENTITY_ONE_LINER__", escaped);
|
|
183
|
+
mid = mid.replace("__DISTRIBUTION_CONTACT_URL__", canonicalOrigin);
|
|
184
|
+
mid = mid.replace("__DISTRIBUTION_INTEGRATE_URL__", integrateUrl);
|
|
185
|
+
mid = mid.replace("__DISTRIBUTION_REPO_URL__", anchors.gitRepositoryUrl);
|
|
186
|
+
mid = mid.replace("__DISTRIBUTION_NPM_URL__", anchors.npmPackageUrl);
|
|
187
|
+
|
|
188
|
+
const repoYaml = mid
|
|
189
|
+
.replace("__SERVERS_ORIGIN__", canonicalOrigin)
|
|
190
|
+
.replace("__OPENAPI_SELF_URL__", openapiSelfCanonical);
|
|
191
|
+
writeFileSync(OPENAPI_OUT, repoYaml, "utf8");
|
|
192
|
+
|
|
193
|
+
mkdirSync(dirname(OPENAPI_PUBLIC), { recursive: true });
|
|
194
|
+
const publicYaml = mid
|
|
195
|
+
.replace("__SERVERS_ORIGIN__", publicOriginNormalized)
|
|
196
|
+
.replace("__OPENAPI_SELF_URL__", openapiSelfEffective);
|
|
197
|
+
writeFileSync(OPENAPI_PUBLIC, publicYaml, "utf8");
|
|
198
|
+
|
|
199
|
+
const discoveryPayload = require("./discovery-payload.lib.cjs");
|
|
200
|
+
const discoveryPayloadObj = discoveryPayload.buildDiscoveryPayload(ROOT);
|
|
201
|
+
const llmsNormalized = discoveryPayload.renderLlmsTextFromPayload(discoveryPayloadObj);
|
|
202
|
+
|
|
203
|
+
mkdirSync(dirname(LLMS_PUBLIC), { recursive: true });
|
|
204
|
+
writeFileSync(LLMS_PUBLIC, llmsNormalized, "utf8");
|
|
205
|
+
writeFileSync(LLMS_REPO_ROOT, llmsNormalized, "utf8");
|
|
206
|
+
|
|
207
|
+
const pkgRaw = readFileSync(PKG_PATH, "utf8");
|
|
208
|
+
const pkg = JSON.parse(pkgRaw);
|
|
209
|
+
pkg.description = String(discovery.pageMetadata.description);
|
|
210
|
+
pkg.repository = { type: "git", url: anchors.gitRepositoryGitUrl };
|
|
211
|
+
pkg.homepage = `${canonicalOrigin}${String(discovery.slug)}`;
|
|
212
|
+
pkg.bugs = { url: anchors.bugsUrl };
|
|
213
|
+
pkg.keywords = anchors.keywords;
|
|
214
|
+
writeFileSync(PKG_PATH, JSON.stringify(pkg, null, 2) + "\n", "utf8");
|
|
215
|
+
|
|
216
|
+
let readme = readFileSync(README_PATH, "utf8");
|
|
217
|
+
if (!readme.includes(DISCOVERY_README_TITLE_START) || !readme.includes(DISCOVERY_README_TITLE_END)) {
|
|
218
|
+
throw new Error("README.md must contain discovery-readme-title markers");
|
|
219
|
+
}
|
|
220
|
+
const titleBody = `# ${String(discovery.readmeTitle)}`;
|
|
221
|
+
const titleBlock = `${DISCOVERY_README_TITLE_START}\n${titleBody}\n${DISCOVERY_README_TITLE_END}`;
|
|
222
|
+
const titleRe = new RegExp(
|
|
223
|
+
`${DISCOVERY_README_TITLE_START.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[\\s\\S]*?${DISCOVERY_README_TITLE_END.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`,
|
|
224
|
+
);
|
|
225
|
+
if (!titleRe.test(readme)) {
|
|
226
|
+
throw new Error("README: could not match discovery-readme-title region");
|
|
227
|
+
}
|
|
228
|
+
readme = readme.replace(titleRe, titleBlock);
|
|
229
|
+
|
|
230
|
+
if (!readme.includes(DISCOVERY_README_START) || !readme.includes(DISCOVERY_README_END)) {
|
|
231
|
+
throw new Error("README.md must contain discovery-acquisition-fold markers");
|
|
232
|
+
}
|
|
233
|
+
const foldBody = discoveryLib.buildDiscoveryFoldBody(discovery, canonicalOrigin);
|
|
234
|
+
const discBlock = `${DISCOVERY_README_START}\n${foldBody}\n${DISCOVERY_README_END}`;
|
|
235
|
+
const discRe = new RegExp(
|
|
236
|
+
`${DISCOVERY_README_START.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[\\s\\S]*?${DISCOVERY_README_END.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`,
|
|
237
|
+
);
|
|
238
|
+
if (!discRe.test(readme)) {
|
|
239
|
+
throw new Error("README: could not match discovery-acquisition-fold region");
|
|
240
|
+
}
|
|
241
|
+
readme = readme.replace(discRe, discBlock);
|
|
242
|
+
|
|
243
|
+
if (!readme.includes(README_START) || !readme.includes(README_END)) {
|
|
244
|
+
throw new Error("README.md must contain public-product-anchors markers");
|
|
245
|
+
}
|
|
246
|
+
const pl = discoveryPayloadObj.links;
|
|
247
|
+
const inner = [
|
|
248
|
+
anchors.identityOneLiner,
|
|
249
|
+
"",
|
|
250
|
+
`- **Repository:** ${anchors.gitRepositoryUrl}`,
|
|
251
|
+
`- **npm package:** ${anchors.npmPackageUrl}`,
|
|
252
|
+
`- **Canonical site:** ${canonicalOrigin}`,
|
|
253
|
+
`- **Integrate:** ${integrateUrl}`,
|
|
254
|
+
`- **OpenAPI (canonical):** ${openapiSelfCanonical}`,
|
|
255
|
+
`- **llms.txt (agents, site):** ${canonicalOrigin}/llms.txt`,
|
|
256
|
+
`- **llms.txt (repo, raw):** ${pl.llmsRaw}`,
|
|
257
|
+
`- **llms.txt (repo, blob):** ${pl.llmsBlob}`,
|
|
258
|
+
"",
|
|
259
|
+
].join("\n");
|
|
260
|
+
const block = `${README_START}\n${inner}\n${README_END}`;
|
|
261
|
+
const re = new RegExp(
|
|
262
|
+
`${README_START.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[\\s\\S]*?${README_END.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`,
|
|
263
|
+
);
|
|
264
|
+
if (!re.test(readme)) {
|
|
265
|
+
throw new Error("README: could not match public-product-anchors region");
|
|
266
|
+
}
|
|
267
|
+
readme = readme.replace(re, block);
|
|
268
|
+
writeFileSync(README_PATH, readme, "utf8");
|
|
269
|
+
|
|
270
|
+
writePublicDistributionGenerated(anchors, discovery);
|
|
271
|
+
writeAgentsMd(anchors, discovery);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function validateForCheck() {
|
|
275
|
+
const discoveryLib = require("./discovery-acquisition.lib.cjs");
|
|
276
|
+
discoveryLib.validateDiscoveryAcquisition(ROOT);
|
|
277
|
+
validateOpenapiTemplate();
|
|
278
|
+
const pm = JSON.parse(readFileSync(MARKETING_PATH, "utf8"));
|
|
279
|
+
const required = [
|
|
280
|
+
"identityOneLiner",
|
|
281
|
+
"productionCanonicalOrigin",
|
|
282
|
+
"gitRepositoryUrl",
|
|
283
|
+
"gitRepositoryGitUrl",
|
|
284
|
+
"npmPackageUrl",
|
|
285
|
+
"bugsUrl",
|
|
286
|
+
"keywords",
|
|
287
|
+
];
|
|
288
|
+
for (const k of required) {
|
|
289
|
+
if (pm[k] === undefined || pm[k] === null) {
|
|
290
|
+
throw new Error(`marketing: missing ${k}`);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
if (!Array.isArray(pm.keywords) || pm.keywords.length === 0) {
|
|
294
|
+
throw new Error("marketing: keywords must be a non-empty array");
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function main() {
|
|
299
|
+
validateForCheck();
|
|
300
|
+
if (process.argv.includes("--check")) {
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
syncPrimaryMarketing();
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/** @deprecated use syncPrimaryMarketing */
|
|
307
|
+
const syncPublicProductAnchors = syncPrimaryMarketing;
|
|
308
|
+
/** @deprecated use validateForCheck */
|
|
309
|
+
const validateAnchors = validateForCheck;
|
|
310
|
+
|
|
311
|
+
module.exports = {
|
|
312
|
+
validateAnchors,
|
|
313
|
+
syncPublicProductAnchors,
|
|
314
|
+
syncPrimaryMarketing,
|
|
315
|
+
assertNextPublicOriginParity,
|
|
316
|
+
normalize,
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
if (require.main === module) {
|
|
320
|
+
try {
|
|
321
|
+
main();
|
|
322
|
+
} catch (e) {
|
|
323
|
+
console.error(e instanceof Error ? e.message : e);
|
|
324
|
+
process.exit(1);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { readFileSync } = require("node:fs");
|
|
4
|
+
const { join } = require("node:path");
|
|
5
|
+
|
|
6
|
+
const ROOT = join(__dirname, "..");
|
|
7
|
+
const MARKETING_PATH = join(ROOT, "config", "marketing.json");
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @param {string} s
|
|
11
|
+
*/
|
|
12
|
+
function normalize(s) {
|
|
13
|
+
const t = String(s).trim();
|
|
14
|
+
if (!t) throw new Error("normalize: empty origin");
|
|
15
|
+
const u = new URL(t);
|
|
16
|
+
return u.origin;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function isLoopbackOrigin(raw) {
|
|
20
|
+
try {
|
|
21
|
+
const u = new URL(normalize(raw));
|
|
22
|
+
const h = u.hostname.toLowerCase();
|
|
23
|
+
return h === "localhost" || h === "127.0.0.1" || h === "::1" || h === "[::1]";
|
|
24
|
+
} catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function readProductionCanonicalOrigin() {
|
|
30
|
+
const pm = JSON.parse(readFileSync(MARKETING_PATH, "utf8"));
|
|
31
|
+
return String(pm.productionCanonicalOrigin);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function assertNextPublicOriginParity() {
|
|
35
|
+
const canonicalFromJson = readProductionCanonicalOrigin();
|
|
36
|
+
const skip = process.env.NODE_ENV !== "production" || process.env.VERCEL_ENV === "preview";
|
|
37
|
+
if (skip) return;
|
|
38
|
+
const url = String(process.env.NEXT_PUBLIC_APP_URL || "").trim();
|
|
39
|
+
if (!url) return;
|
|
40
|
+
if (normalize(url) !== normalize(canonicalFromJson)) {
|
|
41
|
+
if (process.env.VERCEL_ENV !== "production" && isLoopbackOrigin(url)) return;
|
|
42
|
+
throw new Error("NEXT_PUBLIC_APP_URL must equal productionCanonicalOrigin");
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
module.exports = {
|
|
47
|
+
normalize,
|
|
48
|
+
assertNextPublicOriginParity,
|
|
49
|
+
MARKETING_PATH,
|
|
50
|
+
/** @deprecated use MARKETING_PATH */
|
|
51
|
+
PRIMARY_MARKETING_PATH: MARKETING_PATH,
|
|
52
|
+
};
|