@antasphere/chassis-contract 0.0.0-stage → 1.0.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.
Files changed (130) hide show
  1. package/LICENSE +82 -0
  2. package/dist/define.d.ts +177 -0
  3. package/dist/define.d.ts.map +1 -0
  4. package/dist/define.js +35 -0
  5. package/dist/define.js.map +1 -0
  6. package/dist/entitlements.d.ts +486 -0
  7. package/dist/entitlements.d.ts.map +1 -0
  8. package/dist/entitlements.js +344 -0
  9. package/dist/entitlements.js.map +1 -0
  10. package/dist/identity.d.ts +56 -0
  11. package/dist/identity.d.ts.map +1 -0
  12. package/dist/identity.js +2 -0
  13. package/dist/identity.js.map +1 -0
  14. package/dist/index.d.ts +23 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +29 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/routes/index.d.ts +5403 -0
  19. package/dist/routes/index.d.ts.map +1 -0
  20. package/dist/routes/index.js +940 -0
  21. package/dist/routes/index.js.map +1 -0
  22. package/dist/schemas/api-keys.d.ts +54 -0
  23. package/dist/schemas/api-keys.d.ts.map +1 -0
  24. package/dist/schemas/api-keys.js +48 -0
  25. package/dist/schemas/api-keys.js.map +1 -0
  26. package/dist/schemas/audit.d.ts +74 -0
  27. package/dist/schemas/audit.d.ts.map +1 -0
  28. package/dist/schemas/audit.js +65 -0
  29. package/dist/schemas/audit.js.map +1 -0
  30. package/dist/schemas/break-glass.d.ts +42 -0
  31. package/dist/schemas/break-glass.d.ts.map +1 -0
  32. package/dist/schemas/break-glass.js +38 -0
  33. package/dist/schemas/break-glass.js.map +1 -0
  34. package/dist/schemas/cli-auth.d.ts +59 -0
  35. package/dist/schemas/cli-auth.d.ts.map +1 -0
  36. package/dist/schemas/cli-auth.js +68 -0
  37. package/dist/schemas/cli-auth.js.map +1 -0
  38. package/dist/schemas/common.d.ts +96 -0
  39. package/dist/schemas/common.d.ts.map +1 -0
  40. package/dist/schemas/common.js +205 -0
  41. package/dist/schemas/common.js.map +1 -0
  42. package/dist/schemas/demo-passes.d.ts +90 -0
  43. package/dist/schemas/demo-passes.d.ts.map +1 -0
  44. package/dist/schemas/demo-passes.js +60 -0
  45. package/dist/schemas/demo-passes.js.map +1 -0
  46. package/dist/schemas/files.d.ts +39 -0
  47. package/dist/schemas/files.d.ts.map +1 -0
  48. package/dist/schemas/files.js +26 -0
  49. package/dist/schemas/files.js.map +1 -0
  50. package/dist/schemas/instance.d.ts +58 -0
  51. package/dist/schemas/instance.d.ts.map +1 -0
  52. package/dist/schemas/instance.js +70 -0
  53. package/dist/schemas/instance.js.map +1 -0
  54. package/dist/schemas/invitations.d.ts +100 -0
  55. package/dist/schemas/invitations.d.ts.map +1 -0
  56. package/dist/schemas/invitations.js +55 -0
  57. package/dist/schemas/invitations.js.map +1 -0
  58. package/dist/schemas/me.d.ts +81 -0
  59. package/dist/schemas/me.d.ts.map +1 -0
  60. package/dist/schemas/me.js +178 -0
  61. package/dist/schemas/me.js.map +1 -0
  62. package/dist/schemas/members.d.ts +60 -0
  63. package/dist/schemas/members.d.ts.map +1 -0
  64. package/dist/schemas/members.js +43 -0
  65. package/dist/schemas/members.js.map +1 -0
  66. package/dist/schemas/projects.d.ts +232 -0
  67. package/dist/schemas/projects.d.ts.map +1 -0
  68. package/dist/schemas/projects.js +140 -0
  69. package/dist/schemas/projects.js.map +1 -0
  70. package/dist/schemas/scope.d.ts +14 -0
  71. package/dist/schemas/scope.d.ts.map +1 -0
  72. package/dist/schemas/scope.js +5 -0
  73. package/dist/schemas/scope.js.map +1 -0
  74. package/dist/schemas/setup.d.ts +28 -0
  75. package/dist/schemas/setup.d.ts.map +1 -0
  76. package/dist/schemas/setup.js +28 -0
  77. package/dist/schemas/setup.js.map +1 -0
  78. package/dist/schemas/sso-connect.d.ts +30 -0
  79. package/dist/schemas/sso-connect.d.ts.map +1 -0
  80. package/dist/schemas/sso-connect.js +38 -0
  81. package/dist/schemas/sso-connect.js.map +1 -0
  82. package/dist/schemas/sso-logout.d.ts +17 -0
  83. package/dist/schemas/sso-logout.d.ts.map +1 -0
  84. package/dist/schemas/sso-logout.js +16 -0
  85. package/dist/schemas/sso-logout.js.map +1 -0
  86. package/dist/schemas/teams.d.ts +100 -0
  87. package/dist/schemas/teams.d.ts.map +1 -0
  88. package/dist/schemas/teams.js +84 -0
  89. package/dist/schemas/teams.js.map +1 -0
  90. package/dist/schemas/workspaces.d.ts +99 -0
  91. package/dist/schemas/workspaces.d.ts.map +1 -0
  92. package/dist/schemas/workspaces.js +96 -0
  93. package/dist/schemas/workspaces.js.map +1 -0
  94. package/dist/seams.d.ts +185 -0
  95. package/dist/seams.d.ts.map +1 -0
  96. package/dist/seams.js +37 -0
  97. package/dist/seams.js.map +1 -0
  98. package/dist/wire.d.ts +101 -0
  99. package/dist/wire.d.ts.map +1 -0
  100. package/dist/wire.js +161 -0
  101. package/dist/wire.js.map +1 -0
  102. package/package.json +41 -3
  103. package/src/define.ts +64 -0
  104. package/src/entitlements.ts +527 -0
  105. package/src/identity.ts +49 -0
  106. package/src/index.ts +38 -0
  107. package/src/routes/index.ts +1146 -0
  108. package/src/schemas/api-keys.ts +53 -0
  109. package/src/schemas/audit.ts +74 -0
  110. package/src/schemas/break-glass.ts +46 -0
  111. package/src/schemas/cli-auth.ts +78 -0
  112. package/src/schemas/common.ts +206 -0
  113. package/src/schemas/demo-passes.ts +73 -0
  114. package/src/schemas/files.ts +30 -0
  115. package/src/schemas/instance.ts +71 -0
  116. package/src/schemas/invitations.ts +66 -0
  117. package/src/schemas/me.ts +184 -0
  118. package/src/schemas/members.ts +53 -0
  119. package/src/schemas/projects.ts +174 -0
  120. package/src/schemas/scope.ts +18 -0
  121. package/src/schemas/setup.ts +31 -0
  122. package/src/schemas/sso-connect.ts +40 -0
  123. package/src/schemas/sso-logout.ts +17 -0
  124. package/src/schemas/teams.ts +101 -0
  125. package/src/schemas/workspaces.ts +109 -0
  126. package/src/seams.ts +202 -0
  127. package/src/wire.ts +246 -0
  128. package/test/define.test.ts +59 -0
  129. package/test/hub-wire.test.ts +114 -0
  130. package/README.md +0 -3
@@ -0,0 +1,59 @@
1
+ import { describe, expect, expectTypeOf, it } from 'vitest';
2
+ import { defineChassisContract, type ApiKeyInfoOf, type MeResponseOf, type ScopeOf } from '../src/index.js';
3
+ import { defineChassisRoutes } from '../src/routes/index.js';
4
+
5
+ /**
6
+ * The factory is the one place the chassis meets a tool's scope vocabulary.
7
+ * Proven here with scopes that are NOT any real tool's, so the chassis stays
8
+ * honest about never spelling one.
9
+ */
10
+ const a = defineChassisContract({ scopes: ['widgets:read', 'widgets:write'] });
11
+ const b = defineChassisContract({ scopes: ['gadgets:admin'] });
12
+
13
+ describe('defineChassisContract', () => {
14
+ it('builds the scope enum from the scopes it is given, in order', () => {
15
+ expect(a.scopeSchema.options).toEqual(['widgets:read', 'widgets:write']);
16
+ expect(b.scopeSchema.options).toEqual(['gadgets:admin']);
17
+ });
18
+
19
+ it('types Scope as the union of the literals passed in', () => {
20
+ expectTypeOf<ScopeOf<typeof a>>().toEqualTypeOf<'widgets:read' | 'widgets:write'>();
21
+ expectTypeOf<ApiKeyInfoOf<typeof a>['scopes']>().toEqualTypeOf<Array<'widgets:read' | 'widgets:write'>>();
22
+ expectTypeOf<MeResponseOf<typeof b>['scopes']>().toEqualTypeOf<Array<'gadgets:admin'> | null>();
23
+ });
24
+
25
+ it('threads the enum into every schema that carries scopes', () => {
26
+ expect(a.apiKeyCreateSchema.safeParse({ name: 'k', scopes: ['widgets:read'] }).success).toBe(true);
27
+ expect(a.apiKeyCreateSchema.safeParse({ name: 'k', scopes: ['gadgets:admin'] }).success).toBe(false);
28
+ expect(b.apiKeyCreateSchema.safeParse({ name: 'k', scopes: ['gadgets:admin'] }).success).toBe(true);
29
+ expect(a.cliAuthCompletedSchema.shape.apiKey).toBe(a.apiKeySchema);
30
+ expect(a.meResponseSchema.shape.scopes.unwrap().element).toBe(a.scopeSchema);
31
+ });
32
+
33
+ it('holds no module-level state: two instantiations never share a schema', () => {
34
+ expect(a.scopeSchema).not.toBe(b.scopeSchema);
35
+ expect(a.apiKeySchema).not.toBe(b.apiKeySchema);
36
+ expect(a.meResponseSchema).not.toBe(b.meResponseSchema);
37
+ });
38
+ });
39
+
40
+ describe('defineChassisRoutes', () => {
41
+ it('returns the eight route contracts over the instantiated schemas', () => {
42
+ const routes = defineChassisRoutes(
43
+ a,
44
+ { cliKeyScopesLabel: 'widgets:read+write', scopes: { dataExport: 'widgets:export' } },
45
+ { fileInUseOpenApi: 'file_in_use: referenced by a widget' }
46
+ );
47
+ expect(Object.entries(routes).map(([name, r]) => `${name} ${r.method} ${r.path}`)).toEqual([
48
+ 'meRoute get /me',
49
+ 'apiKeysListRoute get /api-keys',
50
+ 'apiKeyCreateRoute post /api-keys',
51
+ 'apiKeyRevokeRoute delete /api-keys/{id}',
52
+ 'cliAuthCompleteRoute post /cli/auth/complete',
53
+ 'ssoCliConnectRoute post /sso/cli-connect',
54
+ 'workspaceExportRoute get /workspace/export',
55
+ 'fileDeleteRoute delete /files/{id}'
56
+ ]);
57
+ expect(routes.meRoute.responses[200].content['application/json'].schema).toBe(a.meResponseSchema);
58
+ });
59
+ });
@@ -0,0 +1,114 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { describe, expect, it } from 'vitest';
5
+ import {
6
+ buildWireSnapshot,
7
+ CHASSIS_WIRE_DEFINITIONS,
8
+ chassisWireSnapshot,
9
+ compareWireSnapshots,
10
+ type HubToolWireSnapshot,
11
+ type WireInputs
12
+ } from '../src/index.js';
13
+
14
+ /**
15
+ * The hub–tool wire check (PRDCT-2677). First the compare itself, on a
16
+ * snapshot the chassis builds from its own copies, so it is proven without
17
+ * any hub file; then the cross-check against the hub's snapshot, found the
18
+ * way `scripts/hub-wire-check.mjs` finds it (`HUB_WIRE_SNAPSHOT`, else the
19
+ * hub checkout beside this repository), skipped when neither is there. CI
20
+ * runs the script against the hub's `dev` (the `hub-wire` job).
21
+ */
22
+
23
+ const ACCOUNT = '0b6c7c1e-4f4e-4a7b-9c1d-2e3f4a5b6c7d';
24
+ const INPUTS: WireInputs = {
25
+ occurrenceOffsetsMs: [0, 5 * 60 * 1000 + 1],
26
+ probes: {
27
+ usageEvent: [{ name: 'empty', input: {} }],
28
+ usageEventsBatch: [{ name: 'empty batch', input: { events: [] } }],
29
+ usageIngestResult: [
30
+ { name: 'no results', input: { results: [], accepted: 0, duplicate: 0, rejected: 0 } }
31
+ ],
32
+ usageEntitlements: [{ name: 'missing everything', input: {} }],
33
+ usageCheckRequest: [
34
+ { name: 'plain', input: { accountRef: ACCOUNT, actionKey: 'things.publish', quantity: 1 } }
35
+ ],
36
+ usageCheck: [
37
+ {
38
+ name: 'unpriceable',
39
+ input: {
40
+ accountRef: ACCOUNT,
41
+ actionKey: 'things.publish',
42
+ quantity: 1,
43
+ allowed: false,
44
+ credits: Number.MAX_SAFE_INTEGER,
45
+ balance: 0,
46
+ unit: 'call',
47
+ priced: true,
48
+ plan: 'free',
49
+ reason: 'unpriceable',
50
+ topUpUrl: 'https://account.example/billing/top-up'
51
+ }
52
+ }
53
+ ]
54
+ }
55
+ };
56
+
57
+ const clone = (s: HubToolWireSnapshot): HubToolWireSnapshot => JSON.parse(JSON.stringify(s));
58
+
59
+ describe('compareWireSnapshots', () => {
60
+ const base = clone(buildWireSnapshot(CHASSIS_WIRE_DEFINITIONS, INPUTS));
61
+
62
+ it('finds nothing between a snapshot and itself, and the chassis rebuilds it on its own inputs', () => {
63
+ expect(compareWireSnapshots(base, clone(base))).toEqual([]);
64
+ expect(compareWireSnapshots(base, clone(chassisWireSnapshot(base)))).toEqual([]);
65
+ });
66
+
67
+ it('names a constant, a probe verdict and a schema leaf by their paths', () => {
68
+ const other = clone(base);
69
+ (other.constants.USAGE_CHECK_REASONS as string[])[2] = 'over_quota';
70
+ other.probes.usageCheck[0]!.ok = !other.probes.usageCheck[0]!.ok;
71
+ const reason = (
72
+ other.schemas.usageCheck as { properties: { reason: { anyOf: Array<{ enum?: string[] }> } } }
73
+ ).properties.reason.anyOf[0]!;
74
+ reason.enum = ['insufficient_credits', 'account_suspended'];
75
+ const differences = compareWireSnapshots(base, other);
76
+ expect(differences.map((d) => d.path)).toEqual([
77
+ 'constants.USAGE_CHECK_REASONS[2]',
78
+ 'probes.usageCheck[0].ok',
79
+ 'schemas.usageCheck.properties.reason.anyOf[0].enum'
80
+ ]);
81
+ expect(differences[0]).toEqual({
82
+ path: 'constants.USAGE_CHECK_REASONS[2]',
83
+ hub: 'unpriceable',
84
+ chassis: 'over_quota'
85
+ });
86
+ });
87
+
88
+ it('treats an absent key as undefined and names an added one', () => {
89
+ const other = clone(base);
90
+ (other.constants.USAGE_ROUTE_ERRORS as Record<string, number | undefined>).payment_required = undefined;
91
+ expect(compareWireSnapshots(base, other)).toEqual([]);
92
+ (other.constants.USAGE_ROUTE_ERRORS as Record<string, number>).payment_required = 402;
93
+ expect(compareWireSnapshots(base, other)).toEqual([
94
+ { path: 'constants.USAGE_ROUTE_ERRORS.payment_required', hub: undefined, chassis: 402 }
95
+ ]);
96
+ });
97
+ });
98
+
99
+ // The hub's file, found as the script finds it: from this package, four levels up is labs/products/antasphere/.
100
+ const PACKAGE_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
101
+ const SIBLING = path.resolve(PACKAGE_DIR, '../../../../hub/packages/contract/wire/hub-tool-messages.json');
102
+ const HUB_FILE = process.env.HUB_WIRE_SNAPSHOT ? path.resolve(process.env.HUB_WIRE_SNAPSHOT) : SIBLING;
103
+
104
+ describe('the chassis’s copies against the hub’s wire snapshot', () => {
105
+ if (!existsSync(HUB_FILE)) {
106
+ it.skip(`skipped: no hub snapshot at ${HUB_FILE} (set HUB_WIRE_SNAPSHOT; CI runs the hub-wire job)`, () => {});
107
+ return;
108
+ }
109
+ it(`agree with ${HUB_FILE}`, () => {
110
+ const hub = JSON.parse(readFileSync(HUB_FILE, 'utf8')) as HubToolWireSnapshot;
111
+ const differences = compareWireSnapshots(hub, clone(chassisWireSnapshot(hub)));
112
+ expect(differences, JSON.stringify(differences, null, 2)).toEqual([]);
113
+ });
114
+ });
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.