@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.
- package/LICENSE +82 -0
- package/dist/define.d.ts +177 -0
- package/dist/define.d.ts.map +1 -0
- package/dist/define.js +35 -0
- package/dist/define.js.map +1 -0
- package/dist/entitlements.d.ts +486 -0
- package/dist/entitlements.d.ts.map +1 -0
- package/dist/entitlements.js +344 -0
- package/dist/entitlements.js.map +1 -0
- package/dist/identity.d.ts +56 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +2 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/routes/index.d.ts +5403 -0
- package/dist/routes/index.d.ts.map +1 -0
- package/dist/routes/index.js +940 -0
- package/dist/routes/index.js.map +1 -0
- package/dist/schemas/api-keys.d.ts +54 -0
- package/dist/schemas/api-keys.d.ts.map +1 -0
- package/dist/schemas/api-keys.js +48 -0
- package/dist/schemas/api-keys.js.map +1 -0
- package/dist/schemas/audit.d.ts +74 -0
- package/dist/schemas/audit.d.ts.map +1 -0
- package/dist/schemas/audit.js +65 -0
- package/dist/schemas/audit.js.map +1 -0
- package/dist/schemas/break-glass.d.ts +42 -0
- package/dist/schemas/break-glass.d.ts.map +1 -0
- package/dist/schemas/break-glass.js +38 -0
- package/dist/schemas/break-glass.js.map +1 -0
- package/dist/schemas/cli-auth.d.ts +59 -0
- package/dist/schemas/cli-auth.d.ts.map +1 -0
- package/dist/schemas/cli-auth.js +68 -0
- package/dist/schemas/cli-auth.js.map +1 -0
- package/dist/schemas/common.d.ts +96 -0
- package/dist/schemas/common.d.ts.map +1 -0
- package/dist/schemas/common.js +205 -0
- package/dist/schemas/common.js.map +1 -0
- package/dist/schemas/demo-passes.d.ts +90 -0
- package/dist/schemas/demo-passes.d.ts.map +1 -0
- package/dist/schemas/demo-passes.js +60 -0
- package/dist/schemas/demo-passes.js.map +1 -0
- package/dist/schemas/files.d.ts +39 -0
- package/dist/schemas/files.d.ts.map +1 -0
- package/dist/schemas/files.js +26 -0
- package/dist/schemas/files.js.map +1 -0
- package/dist/schemas/instance.d.ts +58 -0
- package/dist/schemas/instance.d.ts.map +1 -0
- package/dist/schemas/instance.js +70 -0
- package/dist/schemas/instance.js.map +1 -0
- package/dist/schemas/invitations.d.ts +100 -0
- package/dist/schemas/invitations.d.ts.map +1 -0
- package/dist/schemas/invitations.js +55 -0
- package/dist/schemas/invitations.js.map +1 -0
- package/dist/schemas/me.d.ts +81 -0
- package/dist/schemas/me.d.ts.map +1 -0
- package/dist/schemas/me.js +178 -0
- package/dist/schemas/me.js.map +1 -0
- package/dist/schemas/members.d.ts +60 -0
- package/dist/schemas/members.d.ts.map +1 -0
- package/dist/schemas/members.js +43 -0
- package/dist/schemas/members.js.map +1 -0
- package/dist/schemas/projects.d.ts +232 -0
- package/dist/schemas/projects.d.ts.map +1 -0
- package/dist/schemas/projects.js +140 -0
- package/dist/schemas/projects.js.map +1 -0
- package/dist/schemas/scope.d.ts +14 -0
- package/dist/schemas/scope.d.ts.map +1 -0
- package/dist/schemas/scope.js +5 -0
- package/dist/schemas/scope.js.map +1 -0
- package/dist/schemas/setup.d.ts +28 -0
- package/dist/schemas/setup.d.ts.map +1 -0
- package/dist/schemas/setup.js +28 -0
- package/dist/schemas/setup.js.map +1 -0
- package/dist/schemas/sso-connect.d.ts +30 -0
- package/dist/schemas/sso-connect.d.ts.map +1 -0
- package/dist/schemas/sso-connect.js +38 -0
- package/dist/schemas/sso-connect.js.map +1 -0
- package/dist/schemas/sso-logout.d.ts +17 -0
- package/dist/schemas/sso-logout.d.ts.map +1 -0
- package/dist/schemas/sso-logout.js +16 -0
- package/dist/schemas/sso-logout.js.map +1 -0
- package/dist/schemas/teams.d.ts +100 -0
- package/dist/schemas/teams.d.ts.map +1 -0
- package/dist/schemas/teams.js +84 -0
- package/dist/schemas/teams.js.map +1 -0
- package/dist/schemas/workspaces.d.ts +99 -0
- package/dist/schemas/workspaces.d.ts.map +1 -0
- package/dist/schemas/workspaces.js +96 -0
- package/dist/schemas/workspaces.js.map +1 -0
- package/dist/seams.d.ts +185 -0
- package/dist/seams.d.ts.map +1 -0
- package/dist/seams.js +37 -0
- package/dist/seams.js.map +1 -0
- package/dist/wire.d.ts +101 -0
- package/dist/wire.d.ts.map +1 -0
- package/dist/wire.js +161 -0
- package/dist/wire.js.map +1 -0
- package/package.json +41 -3
- package/src/define.ts +64 -0
- package/src/entitlements.ts +527 -0
- package/src/identity.ts +49 -0
- package/src/index.ts +38 -0
- package/src/routes/index.ts +1146 -0
- package/src/schemas/api-keys.ts +53 -0
- package/src/schemas/audit.ts +74 -0
- package/src/schemas/break-glass.ts +46 -0
- package/src/schemas/cli-auth.ts +78 -0
- package/src/schemas/common.ts +206 -0
- package/src/schemas/demo-passes.ts +73 -0
- package/src/schemas/files.ts +30 -0
- package/src/schemas/instance.ts +71 -0
- package/src/schemas/invitations.ts +66 -0
- package/src/schemas/me.ts +184 -0
- package/src/schemas/members.ts +53 -0
- package/src/schemas/projects.ts +174 -0
- package/src/schemas/scope.ts +18 -0
- package/src/schemas/setup.ts +31 -0
- package/src/schemas/sso-connect.ts +40 -0
- package/src/schemas/sso-logout.ts +17 -0
- package/src/schemas/teams.ts +101 -0
- package/src/schemas/workspaces.ts +109 -0
- package/src/seams.ts +202 -0
- package/src/wire.ts +246 -0
- package/test/define.test.ts +59 -0
- package/test/hub-wire.test.ts +114 -0
- 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