@noodleseed/one 0.153.0 → 0.155.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/dist/commands/app-purge-reconciliation-args.d.ts +28 -0
- package/dist/commands/app-purge-reconciliation-args.d.ts.map +1 -0
- package/dist/commands/app-purge-reconciliation-args.js +124 -0
- package/dist/commands/app-purge-reconciliation-args.js.map +1 -0
- package/dist/commands/app-purge-reconciliation-files.d.ts +8 -0
- package/dist/commands/app-purge-reconciliation-files.d.ts.map +1 -0
- package/dist/commands/app-purge-reconciliation-files.js +109 -0
- package/dist/commands/app-purge-reconciliation-files.js.map +1 -0
- package/dist/commands/app-purge-reconciliation-ops.d.ts +3 -0
- package/dist/commands/app-purge-reconciliation-ops.d.ts.map +1 -0
- package/dist/commands/app-purge-reconciliation-ops.js +190 -0
- package/dist/commands/app-purge-reconciliation-ops.js.map +1 -0
- package/dist/commands/billing-ops.d.ts.map +1 -1
- package/dist/commands/billing-ops.js +7 -0
- package/dist/commands/billing-ops.js.map +1 -1
- package/dist/commands/billing-org-transfer-files.d.ts +12 -0
- package/dist/commands/billing-org-transfer-files.d.ts.map +1 -0
- package/dist/commands/billing-org-transfer-files.js +112 -0
- package/dist/commands/billing-org-transfer-files.js.map +1 -0
- package/dist/commands/billing-org-transfer-ops.d.ts +4 -0
- package/dist/commands/billing-org-transfer-ops.d.ts.map +1 -0
- package/dist/commands/billing-org-transfer-ops.js +534 -0
- package/dist/commands/billing-org-transfer-ops.js.map +1 -0
- package/dist/commands/service-ops.d.ts.map +1 -1
- package/dist/commands/service-ops.js +4 -1
- package/dist/commands/service-ops.js.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/generated/example-files.js +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/skill-embedded-assistant-ref.js +2 -0
- package/node_modules/@noodle-borg/agent-kit/package.json +1 -1
- package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-suggestions.js +5 -3
- package/node_modules/@noodle-borg/assistant-gateway/dist/continuity-bounds.d.ts +36 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/continuity-bounds.js +52 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/continuity-store.d.ts +115 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/continuity-store.js +51 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/in-memory-continuity-store.d.ts +26 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/in-memory-continuity-store.js +80 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/model-request.d.ts +1 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/model-request.js +2 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/model-response-values.js +11 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/model-responses.js +1 -10
- package/node_modules/@noodle-borg/assistant-gateway/dist/model-stream.js +1 -10
- package/node_modules/@noodle-borg/assistant-gateway/dist/portable.d.ts +3 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/portable.js +3 -0
- package/node_modules/@noodle-borg/assistant-gateway/package.json +1 -1
- package/node_modules/@noodle-borg/authoring/dist/assistant.d.ts +35 -0
- package/node_modules/@noodle-borg/authoring/dist/assistant.js +4 -0
- package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-account.js +96 -0
- package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-billing.js +116 -1
- package/node_modules/@noodle-borg/compiler/dist/manifest/branding-schema.js +86 -0
- package/node_modules/@noodle-borg/compiler/dist/manifest/schema.d.ts +44 -25
- package/node_modules/@noodle-borg/compiler/dist/manifest/schema.js +24 -76
- package/node_modules/@noodle-borg/control-plane/dist/app-purge-reconciliation-port.d.ts +25 -0
- package/node_modules/@noodle-borg/control-plane/dist/app-purge-reconciliation-port.js +10 -0
- package/node_modules/@noodle-borg/control-plane/dist/portable.d.ts +1 -0
- package/node_modules/@noodle-borg/control-plane/dist/portable.js +1 -0
- package/node_modules/@noodle-borg/control-plane/package.json +3 -1
- package/node_modules/@noodle-borg/service/dist/routes/app-purge-reconciliation.js +72 -0
- package/node_modules/@noodle-borg/service/dist/routes/control-plane.js +15 -2
- package/node_modules/@noodle-borg/service/dist/service.js +27 -1
- package/node_modules/@noodle-borg/service/dist/store/in-memory.js +4 -8
- package/node_modules/@noodle-borg/service/dist/store/json-file.js +6 -3
- package/node_modules/@noodle-borg/service/dist/store/records.js +20 -0
- package/node_modules/@noodle-borg/service/dist/store.d.ts +3 -2
- package/node_modules/@noodle-borg/service/package.json +1 -1
- package/node_modules/@noodle-borg/wire-contracts/dist/app-purge-reconciliation.d.ts +177 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/app-purge-reconciliation.js +189 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/assistant.d.ts +1 -1
- package/node_modules/@noodle-borg/wire-contracts/dist/billing-org-transfer.d.ts +629 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/billing-org-transfer.js +259 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/control-plane.d.ts +21 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/control-plane.js +23 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/index.d.ts +2 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/index.js +2 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/platform-account-reset.d.ts +4 -4
- package/node_modules/@noodleseed/assistant/package.json +1 -1
- package/package.json +2 -2
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import type { PackagedAssetReference } from '../assets.js';
|
|
3
2
|
type ToolAuthorizationManifest = {
|
|
4
3
|
readonly requiredScopes?: readonly string[] | undefined;
|
|
5
4
|
readonly allowedRoles?: readonly string[] | undefined;
|
|
@@ -381,6 +380,11 @@ export declare const manifestV1Schema: z.ZodObject<{
|
|
|
381
380
|
webmcp: z.ZodOptional<z.ZodObject<{
|
|
382
381
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
383
382
|
}, z.core.$strict>>;
|
|
383
|
+
continuity: z.ZodOptional<z.ZodObject<{
|
|
384
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
385
|
+
windowSeconds: z.ZodOptional<z.ZodNumber>;
|
|
386
|
+
maxRestores: z.ZodOptional<z.ZodNumber>;
|
|
387
|
+
}, z.core.$strict>>;
|
|
384
388
|
}, z.core.$strict>>>;
|
|
385
389
|
sessionClaims: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
386
390
|
exposeToModel: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -395,18 +399,18 @@ export declare const manifestV1Schema: z.ZodObject<{
|
|
|
395
399
|
surface: z.ZodOptional<z.ZodString>;
|
|
396
400
|
surfaceDark: z.ZodOptional<z.ZodString>;
|
|
397
401
|
logo: z.ZodOptional<z.ZodObject<{
|
|
398
|
-
uri: z.ZodUnion<readonly [z.ZodURL, z.ZodType<PackagedAssetReference, unknown, z.core.$ZodTypeInternals<PackagedAssetReference, unknown>>]>;
|
|
399
|
-
darkUri: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodType<PackagedAssetReference, unknown, z.core.$ZodTypeInternals<PackagedAssetReference, unknown>>]>>;
|
|
402
|
+
uri: z.ZodUnion<readonly [z.ZodURL, z.ZodType<import("../assets.js").PackagedAssetReference, unknown, z.core.$ZodTypeInternals<import("../assets.js").PackagedAssetReference, unknown>>]>;
|
|
403
|
+
darkUri: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodType<import("../assets.js").PackagedAssetReference, unknown, z.core.$ZodTypeInternals<import("../assets.js").PackagedAssetReference, unknown>>]>>;
|
|
400
404
|
alt: z.ZodString;
|
|
401
405
|
}, z.core.$strict>>;
|
|
402
406
|
mark: z.ZodOptional<z.ZodObject<{
|
|
403
|
-
uri: z.ZodUnion<readonly [z.ZodURL, z.ZodType<PackagedAssetReference, unknown, z.core.$ZodTypeInternals<PackagedAssetReference, unknown>>]>;
|
|
404
|
-
darkUri: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodType<PackagedAssetReference, unknown, z.core.$ZodTypeInternals<PackagedAssetReference, unknown>>]>>;
|
|
407
|
+
uri: z.ZodUnion<readonly [z.ZodURL, z.ZodType<import("../assets.js").PackagedAssetReference, unknown, z.core.$ZodTypeInternals<import("../assets.js").PackagedAssetReference, unknown>>]>;
|
|
408
|
+
darkUri: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodType<import("../assets.js").PackagedAssetReference, unknown, z.core.$ZodTypeInternals<import("../assets.js").PackagedAssetReference, unknown>>]>>;
|
|
405
409
|
alt: z.ZodString;
|
|
406
410
|
}, z.core.$strict>>;
|
|
407
411
|
avatar: z.ZodOptional<z.ZodObject<{
|
|
408
|
-
uri: z.ZodUnion<readonly [z.ZodURL, z.ZodType<PackagedAssetReference, unknown, z.core.$ZodTypeInternals<PackagedAssetReference, unknown>>]>;
|
|
409
|
-
darkUri: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodType<PackagedAssetReference, unknown, z.core.$ZodTypeInternals<PackagedAssetReference, unknown>>]>>;
|
|
412
|
+
uri: z.ZodUnion<readonly [z.ZodURL, z.ZodType<import("../assets.js").PackagedAssetReference, unknown, z.core.$ZodTypeInternals<import("../assets.js").PackagedAssetReference, unknown>>]>;
|
|
413
|
+
darkUri: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodType<import("../assets.js").PackagedAssetReference, unknown, z.core.$ZodTypeInternals<import("../assets.js").PackagedAssetReference, unknown>>]>>;
|
|
410
414
|
alt: z.ZodString;
|
|
411
415
|
}, z.core.$strict>>;
|
|
412
416
|
theme: z.ZodOptional<z.ZodObject<{
|
|
@@ -864,6 +868,11 @@ export declare const manifestV2Schema: z.ZodObject<{
|
|
|
864
868
|
webmcp: z.ZodOptional<z.ZodObject<{
|
|
865
869
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
866
870
|
}, z.core.$strict>>;
|
|
871
|
+
continuity: z.ZodOptional<z.ZodObject<{
|
|
872
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
873
|
+
windowSeconds: z.ZodOptional<z.ZodNumber>;
|
|
874
|
+
maxRestores: z.ZodOptional<z.ZodNumber>;
|
|
875
|
+
}, z.core.$strict>>;
|
|
867
876
|
}, z.core.$strict>>>;
|
|
868
877
|
sessionClaims: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
869
878
|
exposeToModel: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -878,18 +887,18 @@ export declare const manifestV2Schema: z.ZodObject<{
|
|
|
878
887
|
surface: z.ZodOptional<z.ZodString>;
|
|
879
888
|
surfaceDark: z.ZodOptional<z.ZodString>;
|
|
880
889
|
logo: z.ZodOptional<z.ZodObject<{
|
|
881
|
-
uri: z.ZodUnion<readonly [z.ZodURL, z.ZodType<PackagedAssetReference, unknown, z.core.$ZodTypeInternals<PackagedAssetReference, unknown>>]>;
|
|
882
|
-
darkUri: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodType<PackagedAssetReference, unknown, z.core.$ZodTypeInternals<PackagedAssetReference, unknown>>]>>;
|
|
890
|
+
uri: z.ZodUnion<readonly [z.ZodURL, z.ZodType<import("../assets.js").PackagedAssetReference, unknown, z.core.$ZodTypeInternals<import("../assets.js").PackagedAssetReference, unknown>>]>;
|
|
891
|
+
darkUri: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodType<import("../assets.js").PackagedAssetReference, unknown, z.core.$ZodTypeInternals<import("../assets.js").PackagedAssetReference, unknown>>]>>;
|
|
883
892
|
alt: z.ZodString;
|
|
884
893
|
}, z.core.$strict>>;
|
|
885
894
|
mark: z.ZodOptional<z.ZodObject<{
|
|
886
|
-
uri: z.ZodUnion<readonly [z.ZodURL, z.ZodType<PackagedAssetReference, unknown, z.core.$ZodTypeInternals<PackagedAssetReference, unknown>>]>;
|
|
887
|
-
darkUri: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodType<PackagedAssetReference, unknown, z.core.$ZodTypeInternals<PackagedAssetReference, unknown>>]>>;
|
|
895
|
+
uri: z.ZodUnion<readonly [z.ZodURL, z.ZodType<import("../assets.js").PackagedAssetReference, unknown, z.core.$ZodTypeInternals<import("../assets.js").PackagedAssetReference, unknown>>]>;
|
|
896
|
+
darkUri: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodType<import("../assets.js").PackagedAssetReference, unknown, z.core.$ZodTypeInternals<import("../assets.js").PackagedAssetReference, unknown>>]>>;
|
|
888
897
|
alt: z.ZodString;
|
|
889
898
|
}, z.core.$strict>>;
|
|
890
899
|
avatar: z.ZodOptional<z.ZodObject<{
|
|
891
|
-
uri: z.ZodUnion<readonly [z.ZodURL, z.ZodType<PackagedAssetReference, unknown, z.core.$ZodTypeInternals<PackagedAssetReference, unknown>>]>;
|
|
892
|
-
darkUri: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodType<PackagedAssetReference, unknown, z.core.$ZodTypeInternals<PackagedAssetReference, unknown>>]>>;
|
|
900
|
+
uri: z.ZodUnion<readonly [z.ZodURL, z.ZodType<import("../assets.js").PackagedAssetReference, unknown, z.core.$ZodTypeInternals<import("../assets.js").PackagedAssetReference, unknown>>]>;
|
|
901
|
+
darkUri: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodType<import("../assets.js").PackagedAssetReference, unknown, z.core.$ZodTypeInternals<import("../assets.js").PackagedAssetReference, unknown>>]>>;
|
|
893
902
|
alt: z.ZodString;
|
|
894
903
|
}, z.core.$strict>>;
|
|
895
904
|
theme: z.ZodOptional<z.ZodObject<{
|
|
@@ -1557,6 +1566,11 @@ export declare const manifestSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
1557
1566
|
webmcp: z.ZodOptional<z.ZodObject<{
|
|
1558
1567
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
1559
1568
|
}, z.core.$strict>>;
|
|
1569
|
+
continuity: z.ZodOptional<z.ZodObject<{
|
|
1570
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
1571
|
+
windowSeconds: z.ZodOptional<z.ZodNumber>;
|
|
1572
|
+
maxRestores: z.ZodOptional<z.ZodNumber>;
|
|
1573
|
+
}, z.core.$strict>>;
|
|
1560
1574
|
}, z.core.$strict>>>;
|
|
1561
1575
|
sessionClaims: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
1562
1576
|
exposeToModel: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -1571,18 +1585,18 @@ export declare const manifestSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
1571
1585
|
surface: z.ZodOptional<z.ZodString>;
|
|
1572
1586
|
surfaceDark: z.ZodOptional<z.ZodString>;
|
|
1573
1587
|
logo: z.ZodOptional<z.ZodObject<{
|
|
1574
|
-
uri: z.ZodUnion<readonly [z.ZodURL, z.ZodType<PackagedAssetReference, unknown, z.core.$ZodTypeInternals<PackagedAssetReference, unknown>>]>;
|
|
1575
|
-
darkUri: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodType<PackagedAssetReference, unknown, z.core.$ZodTypeInternals<PackagedAssetReference, unknown>>]>>;
|
|
1588
|
+
uri: z.ZodUnion<readonly [z.ZodURL, z.ZodType<import("../assets.js").PackagedAssetReference, unknown, z.core.$ZodTypeInternals<import("../assets.js").PackagedAssetReference, unknown>>]>;
|
|
1589
|
+
darkUri: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodType<import("../assets.js").PackagedAssetReference, unknown, z.core.$ZodTypeInternals<import("../assets.js").PackagedAssetReference, unknown>>]>>;
|
|
1576
1590
|
alt: z.ZodString;
|
|
1577
1591
|
}, z.core.$strict>>;
|
|
1578
1592
|
mark: z.ZodOptional<z.ZodObject<{
|
|
1579
|
-
uri: z.ZodUnion<readonly [z.ZodURL, z.ZodType<PackagedAssetReference, unknown, z.core.$ZodTypeInternals<PackagedAssetReference, unknown>>]>;
|
|
1580
|
-
darkUri: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodType<PackagedAssetReference, unknown, z.core.$ZodTypeInternals<PackagedAssetReference, unknown>>]>>;
|
|
1593
|
+
uri: z.ZodUnion<readonly [z.ZodURL, z.ZodType<import("../assets.js").PackagedAssetReference, unknown, z.core.$ZodTypeInternals<import("../assets.js").PackagedAssetReference, unknown>>]>;
|
|
1594
|
+
darkUri: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodType<import("../assets.js").PackagedAssetReference, unknown, z.core.$ZodTypeInternals<import("../assets.js").PackagedAssetReference, unknown>>]>>;
|
|
1581
1595
|
alt: z.ZodString;
|
|
1582
1596
|
}, z.core.$strict>>;
|
|
1583
1597
|
avatar: z.ZodOptional<z.ZodObject<{
|
|
1584
|
-
uri: z.ZodUnion<readonly [z.ZodURL, z.ZodType<PackagedAssetReference, unknown, z.core.$ZodTypeInternals<PackagedAssetReference, unknown>>]>;
|
|
1585
|
-
darkUri: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodType<PackagedAssetReference, unknown, z.core.$ZodTypeInternals<PackagedAssetReference, unknown>>]>>;
|
|
1598
|
+
uri: z.ZodUnion<readonly [z.ZodURL, z.ZodType<import("../assets.js").PackagedAssetReference, unknown, z.core.$ZodTypeInternals<import("../assets.js").PackagedAssetReference, unknown>>]>;
|
|
1599
|
+
darkUri: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodType<import("../assets.js").PackagedAssetReference, unknown, z.core.$ZodTypeInternals<import("../assets.js").PackagedAssetReference, unknown>>]>>;
|
|
1586
1600
|
alt: z.ZodString;
|
|
1587
1601
|
}, z.core.$strict>>;
|
|
1588
1602
|
theme: z.ZodOptional<z.ZodObject<{
|
|
@@ -2039,6 +2053,11 @@ export declare const manifestSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
2039
2053
|
webmcp: z.ZodOptional<z.ZodObject<{
|
|
2040
2054
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
2041
2055
|
}, z.core.$strict>>;
|
|
2056
|
+
continuity: z.ZodOptional<z.ZodObject<{
|
|
2057
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
2058
|
+
windowSeconds: z.ZodOptional<z.ZodNumber>;
|
|
2059
|
+
maxRestores: z.ZodOptional<z.ZodNumber>;
|
|
2060
|
+
}, z.core.$strict>>;
|
|
2042
2061
|
}, z.core.$strict>>>;
|
|
2043
2062
|
sessionClaims: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
2044
2063
|
exposeToModel: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -2053,18 +2072,18 @@ export declare const manifestSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
2053
2072
|
surface: z.ZodOptional<z.ZodString>;
|
|
2054
2073
|
surfaceDark: z.ZodOptional<z.ZodString>;
|
|
2055
2074
|
logo: z.ZodOptional<z.ZodObject<{
|
|
2056
|
-
uri: z.ZodUnion<readonly [z.ZodURL, z.ZodType<PackagedAssetReference, unknown, z.core.$ZodTypeInternals<PackagedAssetReference, unknown>>]>;
|
|
2057
|
-
darkUri: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodType<PackagedAssetReference, unknown, z.core.$ZodTypeInternals<PackagedAssetReference, unknown>>]>>;
|
|
2075
|
+
uri: z.ZodUnion<readonly [z.ZodURL, z.ZodType<import("../assets.js").PackagedAssetReference, unknown, z.core.$ZodTypeInternals<import("../assets.js").PackagedAssetReference, unknown>>]>;
|
|
2076
|
+
darkUri: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodType<import("../assets.js").PackagedAssetReference, unknown, z.core.$ZodTypeInternals<import("../assets.js").PackagedAssetReference, unknown>>]>>;
|
|
2058
2077
|
alt: z.ZodString;
|
|
2059
2078
|
}, z.core.$strict>>;
|
|
2060
2079
|
mark: z.ZodOptional<z.ZodObject<{
|
|
2061
|
-
uri: z.ZodUnion<readonly [z.ZodURL, z.ZodType<PackagedAssetReference, unknown, z.core.$ZodTypeInternals<PackagedAssetReference, unknown>>]>;
|
|
2062
|
-
darkUri: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodType<PackagedAssetReference, unknown, z.core.$ZodTypeInternals<PackagedAssetReference, unknown>>]>>;
|
|
2080
|
+
uri: z.ZodUnion<readonly [z.ZodURL, z.ZodType<import("../assets.js").PackagedAssetReference, unknown, z.core.$ZodTypeInternals<import("../assets.js").PackagedAssetReference, unknown>>]>;
|
|
2081
|
+
darkUri: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodType<import("../assets.js").PackagedAssetReference, unknown, z.core.$ZodTypeInternals<import("../assets.js").PackagedAssetReference, unknown>>]>>;
|
|
2063
2082
|
alt: z.ZodString;
|
|
2064
2083
|
}, z.core.$strict>>;
|
|
2065
2084
|
avatar: z.ZodOptional<z.ZodObject<{
|
|
2066
|
-
uri: z.ZodUnion<readonly [z.ZodURL, z.ZodType<PackagedAssetReference, unknown, z.core.$ZodTypeInternals<PackagedAssetReference, unknown>>]>;
|
|
2067
|
-
darkUri: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodType<PackagedAssetReference, unknown, z.core.$ZodTypeInternals<PackagedAssetReference, unknown>>]>>;
|
|
2085
|
+
uri: z.ZodUnion<readonly [z.ZodURL, z.ZodType<import("../assets.js").PackagedAssetReference, unknown, z.core.$ZodTypeInternals<import("../assets.js").PackagedAssetReference, unknown>>]>;
|
|
2086
|
+
darkUri: z.ZodOptional<z.ZodUnion<readonly [z.ZodURL, z.ZodType<import("../assets.js").PackagedAssetReference, unknown, z.core.$ZodTypeInternals<import("../assets.js").PackagedAssetReference, unknown>>]>>;
|
|
2068
2087
|
alt: z.ZodString;
|
|
2069
2088
|
}, z.core.$strict>>;
|
|
2070
2089
|
theme: z.ZodOptional<z.ZodObject<{
|
|
@@ -3,6 +3,7 @@ import { z } from 'zod';
|
|
|
3
3
|
import { MAX_COMPILED_WIDGET_HTML_BYTES, MAX_RAW_WIDGET_HTML_BYTES } from '../widget-limits.js';
|
|
4
4
|
import { agentGuideSchema } from './agent-guide-schema.js';
|
|
5
5
|
import { serverAuthSchema, serverAuthV2Schema } from './auth-schema.js';
|
|
6
|
+
import { assistantOriginOrVariableSchema, httpsUrlSchema, managedVariableExpressionSchema, serverBrandingSchema, } from './branding-schema.js';
|
|
6
7
|
import { NAME_PATTERN } from './naming.js';
|
|
7
8
|
/**
|
|
8
9
|
* Zod schema for Core v1 and v2 manifests (ADRs 0150 and 0157). V1 remains accepted unchanged;
|
|
@@ -133,82 +134,6 @@ const promptSchema = z.object({
|
|
|
133
134
|
arguments: z.array(promptArgumentSchema).optional(),
|
|
134
135
|
fulfilment: fulfilmentSchema,
|
|
135
136
|
});
|
|
136
|
-
const hexColorSchema = z.string().regex(/^#[0-9A-Fa-f]{6}$/, 'must be a 6-digit hex color');
|
|
137
|
-
const httpsUrlSchema = z.url().regex(/^https:\/\//, 'must use https');
|
|
138
|
-
const managedVariableExpressionPattern = /^\$\{env\.[A-Za-z0-9_]+\}$/;
|
|
139
|
-
const managedVariableExpressionSchema = z
|
|
140
|
-
.string()
|
|
141
|
-
.regex(managedVariableExpressionPattern, 'must be an exact managed variable expression');
|
|
142
|
-
// HTTP is allowed only for loopback development origins (mirrors the host-pattern loopback
|
|
143
|
-
// exception used for connector/CSP origins); production embedding origins stay https-only.
|
|
144
|
-
const assistantOriginOrVariablePattern = /^(?:\$\{env\.[A-Za-z0-9_]+\}|https:\/\/[^/?#@\\]+|http:\/\/(?:localhost|127\.0\.0\.1|\[::1\])(?::\d+)?)$/;
|
|
145
|
-
function isCanonicalAssistantOrigin(value) {
|
|
146
|
-
try {
|
|
147
|
-
return new URL(value).origin === value;
|
|
148
|
-
}
|
|
149
|
-
catch {
|
|
150
|
-
return false;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
const assistantOriginOrVariableSchema = z
|
|
154
|
-
.string()
|
|
155
|
-
.regex(assistantOriginOrVariablePattern, 'must be a canonical bare origin using https (http is allowed only for localhost/127.0.0.1/[::1] loopback development origins)')
|
|
156
|
-
.refine((value) => managedVariableExpressionPattern.test(value) || isCanonicalAssistantOrigin(value), 'must be a canonical bare origin');
|
|
157
|
-
const packagedAssetSchema = z
|
|
158
|
-
.object({
|
|
159
|
-
kind: z.literal('asset'),
|
|
160
|
-
sourcePath: z.string().min(1),
|
|
161
|
-
logicalId: z.string().min(1),
|
|
162
|
-
})
|
|
163
|
-
.strict();
|
|
164
|
-
const brandAssetSchema = z
|
|
165
|
-
.object({
|
|
166
|
-
uri: z.union([httpsUrlSchema, packagedAssetSchema]),
|
|
167
|
-
darkUri: z.union([httpsUrlSchema, packagedAssetSchema]).optional(),
|
|
168
|
-
alt: z.string().trim().min(1),
|
|
169
|
-
})
|
|
170
|
-
.strict();
|
|
171
|
-
const brandThemeTokensSchema = z
|
|
172
|
-
.object({
|
|
173
|
-
surface: hexColorSchema.optional(),
|
|
174
|
-
surfaceRaised: hexColorSchema.optional(),
|
|
175
|
-
surfaceMuted: hexColorSchema.optional(),
|
|
176
|
-
text: hexColorSchema.optional(),
|
|
177
|
-
textMuted: hexColorSchema.optional(),
|
|
178
|
-
accent: hexColorSchema.optional(),
|
|
179
|
-
accentText: hexColorSchema.optional(),
|
|
180
|
-
link: hexColorSchema.optional(),
|
|
181
|
-
border: hexColorSchema.optional(),
|
|
182
|
-
borderStrong: hexColorSchema.optional(),
|
|
183
|
-
focus: hexColorSchema.optional(),
|
|
184
|
-
success: hexColorSchema.optional(),
|
|
185
|
-
warning: hexColorSchema.optional(),
|
|
186
|
-
danger: hexColorSchema.optional(),
|
|
187
|
-
code: hexColorSchema.optional(),
|
|
188
|
-
})
|
|
189
|
-
.strict();
|
|
190
|
-
const serverBrandingSchema = z
|
|
191
|
-
.object({
|
|
192
|
-
name: z.string().trim().min(1).optional(),
|
|
193
|
-
accent: hexColorSchema.optional(),
|
|
194
|
-
surface: hexColorSchema.optional(),
|
|
195
|
-
surfaceDark: hexColorSchema.optional(),
|
|
196
|
-
logo: brandAssetSchema.optional(),
|
|
197
|
-
mark: brandAssetSchema.optional(),
|
|
198
|
-
avatar: brandAssetSchema.optional(),
|
|
199
|
-
theme: z
|
|
200
|
-
.object({
|
|
201
|
-
light: brandThemeTokensSchema.optional(),
|
|
202
|
-
dark: brandThemeTokensSchema.optional(),
|
|
203
|
-
})
|
|
204
|
-
.strict()
|
|
205
|
-
.optional(),
|
|
206
|
-
radius: z.enum(['none', 'sm', 'md', 'lg']).optional(),
|
|
207
|
-
density: z.enum(['compact', 'comfortable']).optional(),
|
|
208
|
-
typography: z.enum(['system', 'serif', 'mono']).optional(),
|
|
209
|
-
colorScheme: z.enum(['auto', 'light', 'dark']).optional(),
|
|
210
|
-
})
|
|
211
|
-
.strict();
|
|
212
137
|
const assistantPresentationToneSchema = z.enum(['neutral', 'success', 'warning', 'danger']);
|
|
213
138
|
const optionalStrictObject = (shape) => z.object(shape).strict().optional();
|
|
214
139
|
const assistantPresentationSchema = z
|
|
@@ -357,6 +282,18 @@ const embeddedAssistantSchema = z
|
|
|
357
282
|
// `assistantUiSchema.shape` — this is not renderer presentation, and a surface that
|
|
358
283
|
// acquired it by a spread would be an accident rather than a decision.
|
|
359
284
|
webmcp: optionalStrictObject({ enabled: z.boolean().optional() }),
|
|
285
|
+
// Anonymous cross-page display continuity (ADR 0223, clauses 11-16), declared per public
|
|
286
|
+
// or mixed surface. These bounds mirror the structural ceilings the gateway clamps to at
|
|
287
|
+
// runtime; the ADR is the single source, and this package cannot import the gateway
|
|
288
|
+
// because the dependency runs the other way. Refusing rather than clamping is deliberate:
|
|
289
|
+
// the gateway narrows an operator's value silently by design, but a developer who asks
|
|
290
|
+
// for more than the ceiling has made a mistake, and silence would hide it until someone
|
|
291
|
+
// measured the live behaviour.
|
|
292
|
+
continuity: optionalStrictObject({
|
|
293
|
+
enabled: z.boolean().optional(),
|
|
294
|
+
windowSeconds: z.number().int().min(0).max(600).optional(),
|
|
295
|
+
maxRestores: z.number().int().min(0).max(10).optional(),
|
|
296
|
+
}),
|
|
360
297
|
})
|
|
361
298
|
.strict())
|
|
362
299
|
.min(1)
|
|
@@ -374,6 +311,17 @@ const embeddedAssistantSchema = z
|
|
|
374
311
|
.strict()
|
|
375
312
|
.superRefine((assistant, ctx) => {
|
|
376
313
|
assistant.surfaces?.forEach((surface, index) => {
|
|
314
|
+
// The authenticated direction already reattaches through ADR 0223 clause 7, authorized by a
|
|
315
|
+
// backend-verified subject rather than by possession of a handle. A `continuity` block here
|
|
316
|
+
// would be a developer believing they configured something nothing reads, so refuse it rather
|
|
317
|
+
// than drop it silently.
|
|
318
|
+
if (surface.mode === 'authenticated' && surface.continuity !== undefined) {
|
|
319
|
+
ctx.addIssue({
|
|
320
|
+
code: 'custom',
|
|
321
|
+
path: ['surfaces', index, 'continuity'],
|
|
322
|
+
message: 'continuity belongs on a public or mixed website surface',
|
|
323
|
+
});
|
|
324
|
+
}
|
|
377
325
|
if (surface.mode === 'authenticated')
|
|
378
326
|
return;
|
|
379
327
|
// A public surface fails closed: an omitted allowlist would otherwise read as "expose
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { AppPurgeReconciliationApplyRequestV1, AppPurgeReconciliationApplyResponseV1, AppPurgeReconciliationErrorCodeV1, AppPurgeReconciliationPreviewArtifactV1 } from '@noodle-borg/wire-contracts';
|
|
2
|
+
export interface AppPurgeReconciliationActor {
|
|
3
|
+
readonly subject: string;
|
|
4
|
+
readonly email?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface AppPurgeReconciliationOperator {
|
|
7
|
+
preview(input: {
|
|
8
|
+
readonly releaseSha: string;
|
|
9
|
+
readonly limit: number;
|
|
10
|
+
readonly now: Date;
|
|
11
|
+
}): Promise<AppPurgeReconciliationPreviewArtifactV1>;
|
|
12
|
+
apply(input: {
|
|
13
|
+
readonly request: AppPurgeReconciliationApplyRequestV1;
|
|
14
|
+
readonly actor: AppPurgeReconciliationActor;
|
|
15
|
+
readonly currentReleaseSha: string;
|
|
16
|
+
readonly now: Date;
|
|
17
|
+
}): Promise<AppPurgeReconciliationApplyResponseV1>;
|
|
18
|
+
}
|
|
19
|
+
export type AppPurgeReconciliationConflictCode = Exclude<AppPurgeReconciliationErrorCodeV1, 'app_purge_reconciliation_unavailable'>;
|
|
20
|
+
/** A checked operator conflict; query and transaction failures intentionally remain ordinary errors. */
|
|
21
|
+
export declare class AppPurgeReconciliationError extends Error {
|
|
22
|
+
readonly code: AppPurgeReconciliationConflictCode;
|
|
23
|
+
constructor(code: AppPurgeReconciliationConflictCode, message: string);
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=app-purge-reconciliation-port.d.ts.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** A checked operator conflict; query and transaction failures intentionally remain ordinary errors. */
|
|
2
|
+
export class AppPurgeReconciliationError extends Error {
|
|
3
|
+
code;
|
|
4
|
+
constructor(code, message) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = 'AppPurgeReconciliationError';
|
|
7
|
+
this.code = code;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=app-purge-reconciliation-port.js.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { type AppPurgeReconciliationActor, type AppPurgeReconciliationConflictCode, AppPurgeReconciliationError, type AppPurgeReconciliationOperator, } from './app-purge-reconciliation-port.js';
|
|
1
2
|
export type { ActiveMcpSubdomainClaim, ChangeMcpSubdomainInput, ControlPlaneIdentity, CreateOrgWithOwnerInput, McpSubdomainMutationResult, McpSubdomainSetting, OrganizationStore, OrgDomainRecord, OrgInvitationRecord, OrgMemberRecord, OrgOpenAIAppsChallengeRecord, OrgRecord, OrgRole, PersonalWorkspaceProvisionInput, PersonalWorkspaceProvisionResult, SignupAllowlistKind, SignupAllowlistRecord, WelcomeEmailRecord, } from './contracts.js';
|
|
2
3
|
export { allowAllGate, bearerToken, type ControlPlaneAuthResult, type DeployAuthGate, } from './deploy-auth.js';
|
|
3
4
|
export { CompositeControlPlaneGate, type ControlPlaneSignupMode, GoogleControlPlaneGate, type GoogleControlPlaneGateOptions, type GoogleIdTokenVerifier, GoogleWorkloadControlPlaneGate, type GoogleWorkloadControlPlaneGateOptions, NoodleOAuthControlPlaneGate, type NoodleOAuthControlPlaneGateOptions, type SignupAuthorizer, } from './deploy-gates.js';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { AppPurgeReconciliationError, } from './app-purge-reconciliation-port.js';
|
|
1
2
|
export { allowAllGate, bearerToken, } from './deploy-auth.js';
|
|
2
3
|
export { CompositeControlPlaneGate, GoogleControlPlaneGate, GoogleWorkloadControlPlaneGate, NoodleOAuthControlPlaneGate, } from './deploy-gates.js';
|
|
3
4
|
export { InMemoryControlPlaneStore } from './in-memory-control-plane-store.js';
|
|
@@ -26,7 +26,9 @@
|
|
|
26
26
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@noodle-borg/module": "0.0.0"
|
|
29
|
+
"@noodle-borg/module": "0.0.0",
|
|
30
|
+
"@noodle-borg/module-audit": "0.0.0",
|
|
31
|
+
"@noodle-borg/wire-contracts": "0.0.0"
|
|
30
32
|
},
|
|
31
33
|
"devDependencies": {
|
|
32
34
|
"@types/node": "^24.13.1",
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { AppPurgeReconciliationError, } from '@noodle-borg/control-plane/portable';
|
|
2
|
+
import { readJsonBody, sendJson } from '@noodle-borg/transport-http';
|
|
3
|
+
import { APP_PURGE_RECONCILIATION_MAX_CANDIDATES, AppPurgeReconciliationApplyRequestSchema, AppPurgeReconciliationApplyResponseSchema, AppPurgeReconciliationPreviewRequestSchema, AppPurgeReconciliationPreviewResponseSchema, } from '@noodle-borg/wire-contracts';
|
|
4
|
+
import { sendForbidden } from '../http-util.js';
|
|
5
|
+
import { authorizeControlPlane } from './control-plane.js';
|
|
6
|
+
const UNAVAILABLE = {
|
|
7
|
+
ok: false,
|
|
8
|
+
code: 'app_purge_reconciliation_unavailable',
|
|
9
|
+
error: 'app purge reconciliation is unavailable',
|
|
10
|
+
};
|
|
11
|
+
/** Super-admin-only, exact-set historical repair boundary from ADR 0225. */
|
|
12
|
+
export async function handleAppPurgeReconciliationRoute(req, res, deps, action) {
|
|
13
|
+
const identity = await authorizeControlPlane(req, res, deps.gate, { requireIdentity: true });
|
|
14
|
+
if (identity === false)
|
|
15
|
+
return;
|
|
16
|
+
if (!identity.superAdmin)
|
|
17
|
+
return sendForbidden(res, 'super-admin required');
|
|
18
|
+
const url = new URL(req.url ?? '/', 'http://localhost');
|
|
19
|
+
if (url.search !== '') {
|
|
20
|
+
return sendJson(res, 400, { ok: false, error: 'query parameters are not supported' });
|
|
21
|
+
}
|
|
22
|
+
const contentType = req.headers['content-type']?.split(';', 1)[0]?.trim().toLowerCase();
|
|
23
|
+
if (contentType !== 'application/json') {
|
|
24
|
+
return sendJson(res, 415, { ok: false, error: 'content type must be application/json' });
|
|
25
|
+
}
|
|
26
|
+
const body = await readJsonBody(req, deps.maxBody);
|
|
27
|
+
if (!body.ok)
|
|
28
|
+
return sendJson(res, body.status, { ok: false, error: body.error });
|
|
29
|
+
const parsed = action === 'preview'
|
|
30
|
+
? AppPurgeReconciliationPreviewRequestSchema.safeParse(body.value)
|
|
31
|
+
: AppPurgeReconciliationApplyRequestSchema.safeParse(body.value);
|
|
32
|
+
if (!parsed.success) {
|
|
33
|
+
return sendJson(res, 400, { ok: false, error: 'invalid app purge reconciliation request' });
|
|
34
|
+
}
|
|
35
|
+
if (deps.operator === undefined || !/^[0-9a-f]{40}$/.test(deps.releaseSha)) {
|
|
36
|
+
return sendJson(res, 503, UNAVAILABLE);
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const now = deps.clock?.() ?? new Date();
|
|
40
|
+
if (action === 'preview') {
|
|
41
|
+
const request = AppPurgeReconciliationPreviewRequestSchema.parse(parsed.data);
|
|
42
|
+
const artifact = await deps.operator.preview({
|
|
43
|
+
releaseSha: deps.releaseSha,
|
|
44
|
+
limit: request.limit ?? APP_PURGE_RECONCILIATION_MAX_CANDIDATES,
|
|
45
|
+
now,
|
|
46
|
+
});
|
|
47
|
+
return sendJson(res, 200, AppPurgeReconciliationPreviewResponseSchema.parse({ ok: true, artifact }));
|
|
48
|
+
}
|
|
49
|
+
const request = AppPurgeReconciliationApplyRequestSchema.parse(parsed.data);
|
|
50
|
+
const response = await deps.operator.apply({
|
|
51
|
+
request,
|
|
52
|
+
actor: {
|
|
53
|
+
subject: identity.subject,
|
|
54
|
+
...(identity.email === undefined ? {} : { email: identity.email }),
|
|
55
|
+
},
|
|
56
|
+
currentReleaseSha: deps.releaseSha,
|
|
57
|
+
now,
|
|
58
|
+
});
|
|
59
|
+
return sendJson(res, 200, AppPurgeReconciliationApplyResponseSchema.parse(response));
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
if (error instanceof AppPurgeReconciliationError) {
|
|
63
|
+
return sendJson(res, 409, {
|
|
64
|
+
ok: false,
|
|
65
|
+
code: error.code,
|
|
66
|
+
error: 'app purge reconciliation request conflicts with current state',
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return sendJson(res, 503, UNAVAILABLE);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=app-purge-reconciliation.js.map
|
|
@@ -3,7 +3,7 @@ import { ensurePersonalWorkspace } from '@noodle-borg/control-plane/portable';
|
|
|
3
3
|
import { DEVELOPER_ASSISTANT_PATH, DEVELOPER_CLI_PATH, } from '@noodle-borg/developer-mcp';
|
|
4
4
|
import { normalizeServerVersion } from '@noodle-borg/module';
|
|
5
5
|
import { noopLogger, readDeployBody, sendJson } from '@noodle-borg/transport-http';
|
|
6
|
-
import { deployRequestSchema, formatWireError, } from '@noodle-borg/wire-contracts';
|
|
6
|
+
import { deployRequestSchema, formatWireError, WhoamiIdentityResponseSchema, } from '@noodle-borg/wire-contracts';
|
|
7
7
|
import { authorizeDeveloperGrant, } from '../auth/developer-grant-guard.js';
|
|
8
8
|
import { baseFromRequest, sendForbidden, sendUnauthorized } from '../http-util.js';
|
|
9
9
|
import { endpointUrlOptionsForOrg } from '../mcp-public-routing.js';
|
|
@@ -443,7 +443,7 @@ export async function authorizeDeploymentOwnerSelection(res, controlPlane, org,
|
|
|
443
443
|
}
|
|
444
444
|
return { ok: true, ownerSubject: requestedOwnerSubject };
|
|
445
445
|
}
|
|
446
|
-
export async function handleWhoami(req, res, gate, controlPlane, options = {}) {
|
|
446
|
+
export async function handleWhoami(req, res, gate, controlPlane, options = {}, scope) {
|
|
447
447
|
// Identity introspection names no org or environment, so no grant context can describe it.
|
|
448
448
|
const identity = await authorizeControlPlane(req, res, gate, {
|
|
449
449
|
requireIdentity: true,
|
|
@@ -451,6 +451,19 @@ export async function handleWhoami(req, res, gate, controlPlane, options = {}) {
|
|
|
451
451
|
});
|
|
452
452
|
if (identity === false)
|
|
453
453
|
return;
|
|
454
|
+
if (scope === 'identity') {
|
|
455
|
+
const response = WhoamiIdentityResponseSchema.parse({
|
|
456
|
+
ok: true,
|
|
457
|
+
data: {
|
|
458
|
+
identity: {
|
|
459
|
+
subject: identity.subject,
|
|
460
|
+
email: identity.email,
|
|
461
|
+
superAdmin: identity.superAdmin,
|
|
462
|
+
},
|
|
463
|
+
},
|
|
464
|
+
});
|
|
465
|
+
return sendJson(res, 200, response);
|
|
466
|
+
}
|
|
454
467
|
if (!identity.superAdmin && options.controlPlaneSignupMode === 'public') {
|
|
455
468
|
await ensurePersonalWorkspace(controlPlane, identity);
|
|
456
469
|
}
|
|
@@ -23,6 +23,7 @@ import { isAuthServerPath } from './oauth/paths.js';
|
|
|
23
23
|
import { createIntentTargetResolver, createObservabilityDispatcher, createObservabilityStores, } from './observability-runtime.js';
|
|
24
24
|
import { handleAccessUpdate } from './routes/access.js';
|
|
25
25
|
import { dispatchAlertRoutes } from './routes/alerts-dispatch.js';
|
|
26
|
+
import { handleAppPurgeReconciliationRoute, } from './routes/app-purge-reconciliation.js';
|
|
26
27
|
import { handleAppArchive, handleAppRestore } from './routes/archive.js';
|
|
27
28
|
import { handleAssetPreflight } from './routes/asset-control-plane.js';
|
|
28
29
|
import { dispatchAssistantRoutes } from './routes/assistant-dispatch.js';
|
|
@@ -233,6 +234,26 @@ export function createServiceHandler(registry, options = {}) {
|
|
|
233
234
|
...(advanced ? { modules: capabilityReport.modules } : {}),
|
|
234
235
|
});
|
|
235
236
|
}
|
|
237
|
+
const appPurgeReconciliationAction = url.pathname === '/v1/service/app-purge-reconciliation/preview'
|
|
238
|
+
? 'preview'
|
|
239
|
+
: url.pathname === '/v1/service/app-purge-reconciliation/apply'
|
|
240
|
+
? 'apply'
|
|
241
|
+
: undefined;
|
|
242
|
+
if (req.method === 'POST' && appPurgeReconciliationAction !== undefined) {
|
|
243
|
+
applySecurityHeaders(res, tls);
|
|
244
|
+
if (enforceHttps(req, res, tls))
|
|
245
|
+
return;
|
|
246
|
+
void handleAppPurgeReconciliationRoute(req, res, {
|
|
247
|
+
gate,
|
|
248
|
+
...(options.appPurgeReconciliationOperator === undefined
|
|
249
|
+
? {}
|
|
250
|
+
: { operator: options.appPurgeReconciliationOperator }),
|
|
251
|
+
releaseSha: buildInfo.gitSha,
|
|
252
|
+
maxBody,
|
|
253
|
+
...(options.clock === undefined ? {} : { clock: options.clock }),
|
|
254
|
+
}, appPurgeReconciliationAction);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
236
257
|
if (servicePrincipalDispatcher?.(req, res, url))
|
|
237
258
|
return;
|
|
238
259
|
if (dispatchAssistantRoutes(req, res, url, {
|
|
@@ -316,7 +337,12 @@ export function createServiceHandler(registry, options = {}) {
|
|
|
316
337
|
applySecurityHeaders(res, tls);
|
|
317
338
|
if (enforceHttps(req, res, tls))
|
|
318
339
|
return;
|
|
319
|
-
|
|
340
|
+
const scopes = url.searchParams.getAll('scope');
|
|
341
|
+
if (scopes.length > 1 || (scopes.length === 1 && scopes[0] !== 'identity')) {
|
|
342
|
+
sendJson(res, 400, { error: 'invalid whoami scope' });
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
handleWhoami(req, res, gate, controlPlane, options, scopes[0] === 'identity' ? 'identity' : undefined).catch(() => {
|
|
320
346
|
if (!res.headersSent)
|
|
321
347
|
sendJson(res, 500, { error: 'internal error' });
|
|
322
348
|
});
|
|
@@ -3,7 +3,7 @@ import { assertSameAppPackageSnapshot, sanitizeDeployRecordAppPackageSnapshot, }
|
|
|
3
3
|
import { assertCustomerAuthRestorePrecondition, assertUniqueActiveCustomerAuthAudienceBindings, findActiveCustomerAuthAudienceConflict, } from '../customer-auth-audience-binding.js';
|
|
4
4
|
import { assertDeploymentActivationUnlocked, assertDeploymentAppendUnlocked, } from '../deployment-lock.js';
|
|
5
5
|
import { defaultActiveRecord, sameDeploymentScope, sameTenantRecord, } from '../deployment-versioning.js';
|
|
6
|
-
import { appArchivedAt, deploymentSummary, matchesDeploymentFilter, paginateAppSummaries, planAppArchive, planAppRestore, preserveDeploymentOwnerState, resolveActiveAccessUpdate, resolveProductionEnvironment, summarizeApps, summarizeEnvs, validateDeploymentListFilter, withoutArchiveStamp, } from './records.js';
|
|
6
|
+
import { appArchivedAt, deploymentSummary, matchesDeploymentFilter, paginateAppSummaries, planAppArchive, planAppRestore, planArchivedAppSweep, preserveDeploymentOwnerState, resolveActiveAccessUpdate, resolveProductionEnvironment, summarizeApps, summarizeEnvs, validateDeploymentListFilter, withoutArchiveStamp, } from './records.js';
|
|
7
7
|
import { validateSlug, validateTenantRef } from './validate.js';
|
|
8
8
|
/** In-memory store: keeps records in a Map. Used by tests and as an explicit, non-persistent option. */
|
|
9
9
|
export class InMemoryArtifactStore {
|
|
@@ -165,13 +165,9 @@ export class InMemoryArtifactStore {
|
|
|
165
165
|
return Promise.resolve(plan.result);
|
|
166
166
|
}
|
|
167
167
|
sweepArchived(before) {
|
|
168
|
-
const deleted = [];
|
|
169
|
-
for (const
|
|
170
|
-
|
|
171
|
-
deleted.push(record);
|
|
172
|
-
this.#records.delete(id);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
168
|
+
const deleted = planArchivedAppSweep([...this.#records.values()], before);
|
|
169
|
+
for (const record of deleted)
|
|
170
|
+
this.#records.delete(record.deploymentId);
|
|
175
171
|
return Promise.resolve(deleted);
|
|
176
172
|
}
|
|
177
173
|
async listApps(org, opts = {}) {
|
|
@@ -6,7 +6,7 @@ import { assertSameAppPackageSnapshot, sanitizeDeployRecordAppPackageSnapshot, }
|
|
|
6
6
|
import { assertCustomerAuthRestorePrecondition, assertUniqueActiveCustomerAuthAudienceBindings, findActiveCustomerAuthAudienceConflict, } from '../customer-auth-audience-binding.js';
|
|
7
7
|
import { assertDeploymentActivationUnlocked, assertDeploymentAppendUnlocked, } from '../deployment-lock.js';
|
|
8
8
|
import { defaultActiveRecord, sameDeploymentScope, sameTenantRecord, } from '../deployment-versioning.js';
|
|
9
|
-
import { appArchivedAt, deploymentSummary, matchesDeploymentFilter, paginateAppSummaries, planAppArchive, planAppRestore, preserveDeploymentOwnerState, resolveActiveAccessUpdate, resolveProductionEnvironment, summarizeApps, summarizeEnvs, validateDeploymentListFilter, withoutArchiveStamp, } from './records.js';
|
|
9
|
+
import { appArchivedAt, deploymentSummary, matchesDeploymentFilter, paginateAppSummaries, planAppArchive, planAppRestore, planArchivedAppSweep, preserveDeploymentOwnerState, resolveActiveAccessUpdate, resolveProductionEnvironment, summarizeApps, summarizeEnvs, validateDeploymentListFilter, withoutArchiveStamp, } from './records.js';
|
|
10
10
|
import { DEPLOYMENT_ID_PATTERN, validateSlug, validateTenantRef } from './validate.js';
|
|
11
11
|
/**
|
|
12
12
|
* JSON-file store: one file per deployment at `<dataDir>/deployments/<deploymentId>.json`, written atomically
|
|
@@ -228,8 +228,11 @@ export class JsonFileArtifactStore {
|
|
|
228
228
|
await Promise.all(plan.clear.map((record) => this.#writeRecord(withoutArchiveStamp(record))));
|
|
229
229
|
return plan.result;
|
|
230
230
|
}
|
|
231
|
-
|
|
232
|
-
|
|
231
|
+
sweepArchived(before) {
|
|
232
|
+
return this.#serializeLifecycle(() => this.#sweepArchivedUnlocked(before));
|
|
233
|
+
}
|
|
234
|
+
async #sweepArchivedUnlocked(before) {
|
|
235
|
+
const deleted = planArchivedAppSweep(await this.loadAll(), before);
|
|
233
236
|
await Promise.all(deleted.map((record) => rm(join(this.#dir, `${record.deploymentId}.json`), { force: true })));
|
|
234
237
|
return deleted;
|
|
235
238
|
}
|
|
@@ -101,6 +101,26 @@ export function planAppRestore(records) {
|
|
|
101
101
|
const clear = records.filter((record) => record.archivedAt !== undefined);
|
|
102
102
|
return { result: { restoredDeployments: clear.length }, clear };
|
|
103
103
|
}
|
|
104
|
+
/** Plan a retention sweep: only delete an app when every deployment is archived before the cutoff. */
|
|
105
|
+
export function planArchivedAppSweep(records, before) {
|
|
106
|
+
const apps = new Map();
|
|
107
|
+
for (const record of records) {
|
|
108
|
+
let byApp = apps.get(record.orgSlug);
|
|
109
|
+
if (byApp === undefined) {
|
|
110
|
+
byApp = new Map();
|
|
111
|
+
apps.set(record.orgSlug, byApp);
|
|
112
|
+
}
|
|
113
|
+
const bucket = byApp.get(record.appSlug);
|
|
114
|
+
if (bucket === undefined)
|
|
115
|
+
byApp.set(record.appSlug, [record]);
|
|
116
|
+
else
|
|
117
|
+
bucket.push(record);
|
|
118
|
+
}
|
|
119
|
+
return [...apps.values()].flatMap((byApp) => [...byApp.values()].flatMap((appRecords) => appRecords.length > 0 &&
|
|
120
|
+
appRecords.every((record) => record.archivedAt !== undefined && record.archivedAt < before)
|
|
121
|
+
? appRecords
|
|
122
|
+
: []));
|
|
123
|
+
}
|
|
104
124
|
/** Strip the archive stamp from a record (exact-optional safe). */
|
|
105
125
|
export function withoutArchiveStamp(record) {
|
|
106
126
|
const { archivedAt: _cleared, ...rest } = record;
|
|
@@ -318,8 +318,9 @@ export interface ArtifactStore {
|
|
|
318
318
|
* App soft delete (ADR 0117). `getAppArchivedAt` reports the app's archived stamp (defined iff the
|
|
319
319
|
* app has records and every record is stamped). `archiveApp` stamps every record for the app (all
|
|
320
320
|
* environments/versions); `restoreApp` clears the stamps; both resolve `undefined` for an app with
|
|
321
|
-
* no records. `sweepArchived` hard-deletes
|
|
322
|
-
*
|
|
321
|
+
* no records. `sweepArchived` hard-deletes a complete app only when every one of its records is archived
|
|
322
|
+
* strictly before `before`, returning every record from each deleted app so the caller can reclaim
|
|
323
|
+
* associated config and emit audit events.
|
|
323
324
|
*/
|
|
324
325
|
getAppArchivedAt(org: string, app: string): Promise<string | undefined>;
|
|
325
326
|
archiveApp(org: string, app: string, at: string): Promise<AppArchiveResult | undefined>;
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
41
41
|
"@noodle-borg/admission-limits": "0.0.0",
|
|
42
|
-
"@noodle-borg/agent-kit": "0.
|
|
42
|
+
"@noodle-borg/agent-kit": "0.93.0",
|
|
43
43
|
"@noodle-borg/app-package": "0.0.0",
|
|
44
44
|
"@noodle-borg/assistant-gateway": "0.0.0",
|
|
45
45
|
"@noodle-borg/auth": "0.0.0",
|