@ankhorage/contracts 1.18.3 → 1.19.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/CHANGELOG.md +6 -0
- package/README.md +45 -0
- package/dist/cli.d.ts +23 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +5 -1
- package/src/cli.test.ts +88 -0
- package/src/cli.ts +27 -0
- package/src/contracts.test.ts +12 -1
- package/src/index.ts +1 -0
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -22,6 +22,7 @@ Shared public contracts for Ankhorage packages and standalone provider packages.
|
|
|
22
22
|
```ts
|
|
23
23
|
import type { AppManifest } from '@ankhorage/contracts';
|
|
24
24
|
import type { AuthAdapter } from '@ankhorage/contracts/auth';
|
|
25
|
+
import type { AnkhCommandProviderManifest, AnkhPackageMetadata } from '@ankhorage/contracts/cli';
|
|
25
26
|
import type { DbAdapter } from '@ankhorage/contracts/db';
|
|
26
27
|
import type { StorageAdapter } from '@ankhorage/contracts/storage';
|
|
27
28
|
```
|
|
@@ -71,6 +72,50 @@ export function createSupabaseAuthAdapter(): AuthAdapter {
|
|
|
71
72
|
}
|
|
72
73
|
```
|
|
73
74
|
|
|
75
|
+
## CLI discovery contracts
|
|
76
|
+
|
|
77
|
+
`@ankhorage/contracts/cli` contains metadata-only discovery contracts for Ankh
|
|
78
|
+
packages and command providers.
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import type { AnkhCommandProviderManifest, AnkhPackageMetadata } from '@ankhorage/contracts/cli';
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Provider packages expose `package.json.ankh` metadata using a package-relative
|
|
85
|
+
provider module path:
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"ankh": {
|
|
90
|
+
"category": "infra",
|
|
91
|
+
"provider": "./dist/ankh.provider.js",
|
|
92
|
+
"capabilities": ["infra.up", "infra.status"]
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Metadata-only packages use `null` for `provider`:
|
|
98
|
+
|
|
99
|
+
```json
|
|
100
|
+
{
|
|
101
|
+
"ankh": {
|
|
102
|
+
"category": "contracts",
|
|
103
|
+
"provider": null,
|
|
104
|
+
"capabilities": ["contracts.cli"]
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Command descriptor paths are relative to the provider category:
|
|
110
|
+
|
|
111
|
+
- `category: "infra"` with `path: ["up"]` maps to `ankh infra up`
|
|
112
|
+
- `category: "dev"` with `path: ["android", "scan"]` maps to `ankh dev android scan`
|
|
113
|
+
|
|
114
|
+
This subpath contains contracts only. It must not depend on `commander`,
|
|
115
|
+
`@ankhorage/ankh`, provider implementations, or runtime CLI execution logic.
|
|
116
|
+
Concrete `package.json.ankh` adoption for this package is deferred to
|
|
117
|
+
`contracts#84`.
|
|
118
|
+
|
|
74
119
|
## Profile contract
|
|
75
120
|
|
|
76
121
|
Auth providers own identity records. App-facing profile data should be modeled separately, usually in an app table such as `profiles`.
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type AnkhCommandCategory = string;
|
|
2
|
+
export type AnkhProviderReference = `./${string}`;
|
|
3
|
+
export type AnkhCapabilityId = `${string}.${string}`;
|
|
4
|
+
export interface AnkhCommandDescriptor {
|
|
5
|
+
readonly path: readonly [string, ...string[]];
|
|
6
|
+
readonly summary: string;
|
|
7
|
+
readonly capability: AnkhCapabilityId;
|
|
8
|
+
readonly aliases?: readonly string[];
|
|
9
|
+
readonly examples?: readonly string[];
|
|
10
|
+
}
|
|
11
|
+
export interface AnkhCommandProviderManifest {
|
|
12
|
+
readonly id: string;
|
|
13
|
+
readonly category: AnkhCommandCategory;
|
|
14
|
+
readonly version: string;
|
|
15
|
+
readonly capabilities: readonly AnkhCapabilityId[];
|
|
16
|
+
readonly commands: readonly AnkhCommandDescriptor[];
|
|
17
|
+
}
|
|
18
|
+
export interface AnkhPackageMetadata {
|
|
19
|
+
readonly category: AnkhCommandCategory;
|
|
20
|
+
readonly provider: AnkhProviderReference | null;
|
|
21
|
+
readonly capabilities: readonly AnkhCapabilityId[];
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAEzC,MAAM,MAAM,qBAAqB,GAAG,KAAK,MAAM,EAAE,CAAC;AAElD,MAAM,MAAM,gBAAgB,GAAG,GAAG,MAAM,IAAI,MAAM,EAAE,CAAC;AAErD,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;IAC9C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC;IACtC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,YAAY,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACnD,QAAQ,CAAC,QAAQ,EAAE,SAAS,qBAAqB,EAAE,CAAC;CACrD;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC;IACvC,QAAQ,CAAC,QAAQ,EAAE,qBAAqB,GAAG,IAAI,CAAC;IAChD,QAAQ,CAAC,YAAY,EAAE,SAAS,gBAAgB,EAAE,CAAC;CACpD"}
|
package/dist/cli.js
ADDED
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"","sourcesContent":["export type AnkhCommandCategory = string;\n\nexport type AnkhProviderReference = `./${string}`;\n\nexport type AnkhCapabilityId = `${string}.${string}`;\n\nexport interface AnkhCommandDescriptor {\n readonly path: readonly [string, ...string[]];\n readonly summary: string;\n readonly capability: AnkhCapabilityId;\n readonly aliases?: readonly string[];\n readonly examples?: readonly string[];\n}\n\nexport interface AnkhCommandProviderManifest {\n readonly id: string;\n readonly category: AnkhCommandCategory;\n readonly version: string;\n readonly capabilities: readonly AnkhCapabilityId[];\n readonly commands: readonly AnkhCommandDescriptor[];\n}\n\nexport interface AnkhPackageMetadata {\n readonly category: AnkhCommandCategory;\n readonly provider: AnkhProviderReference | null;\n readonly capabilities: readonly AnkhCapabilityId[];\n}\n"]}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,QAAQ,CAAC;AACvB,cAAc,MAAM,CAAC;AACrB,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,MAAM,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,OAAO,CAAC;AACtB,cAAc,QAAQ,CAAC;AACvB,cAAc,MAAM,CAAC;AACrB,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,MAAM,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,QAAQ,CAAC;AACvB,cAAc,MAAM,CAAC;AACrB,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,MAAM,CAAC","sourcesContent":["export * from './auth';\nexport * from './bindings';\nexport * from './data';\nexport * from './db';\nexport * from './nutrition';\nexport * from './requirements';\nexport * from './state';\nexport * from './storage';\nexport * from './types';\nexport * from './ui';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,OAAO,CAAC;AACtB,cAAc,QAAQ,CAAC;AACvB,cAAc,MAAM,CAAC;AACrB,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,MAAM,CAAC","sourcesContent":["export * from './auth';\nexport * from './bindings';\nexport * from './cli';\nexport * from './data';\nexport * from './db';\nexport * from './nutrition';\nexport * from './requirements';\nexport * from './state';\nexport * from './storage';\nexport * from './types';\nexport * from './ui';\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ankhorage/contracts",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.19.0",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@ankhorage/color-theory": "^0.0.7"
|
|
@@ -25,6 +25,10 @@
|
|
|
25
25
|
"types": "./dist/bindings.d.ts",
|
|
26
26
|
"default": "./dist/bindings.js"
|
|
27
27
|
},
|
|
28
|
+
"./cli": {
|
|
29
|
+
"types": "./dist/cli.d.ts",
|
|
30
|
+
"default": "./dist/cli.js"
|
|
31
|
+
},
|
|
28
32
|
"./data": {
|
|
29
33
|
"types": "./dist/data/index.d.ts",
|
|
30
34
|
"default": "./dist/data/index.js"
|
package/src/cli.test.ts
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { describe, expect, it } from 'bun:test';
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
AnkhCapabilityId,
|
|
5
|
+
AnkhCommandDescriptor,
|
|
6
|
+
AnkhCommandProviderManifest,
|
|
7
|
+
AnkhPackageMetadata,
|
|
8
|
+
} from './index';
|
|
9
|
+
|
|
10
|
+
describe('cli contracts', () => {
|
|
11
|
+
it('accepts provider package metadata and provider manifests', () => {
|
|
12
|
+
const packageMetadata = {
|
|
13
|
+
category: 'infra',
|
|
14
|
+
provider: './dist/ankh.provider.js',
|
|
15
|
+
capabilities: ['infra.up', 'infra.status'],
|
|
16
|
+
} as const satisfies AnkhPackageMetadata;
|
|
17
|
+
|
|
18
|
+
const upCommand = {
|
|
19
|
+
path: ['up'],
|
|
20
|
+
summary: 'Bring project infrastructure up',
|
|
21
|
+
capability: 'infra.up',
|
|
22
|
+
aliases: ['start'],
|
|
23
|
+
examples: ['ankh infra up shop'],
|
|
24
|
+
} as const satisfies AnkhCommandDescriptor;
|
|
25
|
+
|
|
26
|
+
const manifest = {
|
|
27
|
+
id: '@ankhorage/infra',
|
|
28
|
+
category: 'infra',
|
|
29
|
+
version: '1.0.0',
|
|
30
|
+
capabilities: ['infra.up', 'infra.status'],
|
|
31
|
+
commands: [upCommand],
|
|
32
|
+
} as const satisfies AnkhCommandProviderManifest;
|
|
33
|
+
|
|
34
|
+
expect(JSON.parse(JSON.stringify(packageMetadata))).toEqual(packageMetadata);
|
|
35
|
+
expect(JSON.parse(JSON.stringify(manifest))).toEqual(manifest);
|
|
36
|
+
expect(manifest.id).toBe('@ankhorage/infra');
|
|
37
|
+
expect(manifest.category).toBe('infra');
|
|
38
|
+
expect(manifest.commands[0].path).toEqual(['up']);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('accepts metadata-only packages without a provider module', () => {
|
|
42
|
+
const packageMetadata = {
|
|
43
|
+
category: 'contracts',
|
|
44
|
+
provider: null,
|
|
45
|
+
capabilities: ['contracts.cli'],
|
|
46
|
+
} as const satisfies AnkhPackageMetadata;
|
|
47
|
+
|
|
48
|
+
expect(JSON.parse(JSON.stringify(packageMetadata))).toEqual(packageMetadata);
|
|
49
|
+
expect(packageMetadata.provider).toBeNull();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('keeps command paths relative to the provider category', () => {
|
|
53
|
+
const androidScanCommand = {
|
|
54
|
+
path: ['android', 'scan'],
|
|
55
|
+
summary: 'Scan an Android target',
|
|
56
|
+
capability: 'dev.android.scan',
|
|
57
|
+
examples: ['ankh dev android scan'],
|
|
58
|
+
} as const satisfies AnkhCommandDescriptor;
|
|
59
|
+
|
|
60
|
+
const manifest = {
|
|
61
|
+
id: '@ankhorage/dev',
|
|
62
|
+
category: 'dev',
|
|
63
|
+
version: '1.0.0',
|
|
64
|
+
capabilities: ['dev.android.scan'],
|
|
65
|
+
commands: [androidScanCommand],
|
|
66
|
+
} as const satisfies AnkhCommandProviderManifest;
|
|
67
|
+
|
|
68
|
+
expect(manifest.category).toBe('dev');
|
|
69
|
+
expect(manifest.commands[0].path).toEqual(['android', 'scan']);
|
|
70
|
+
expect(manifest.commands[0].path[0]).not.toBe(manifest.category);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('accepts dot-separated capability ids for discovery metadata', () => {
|
|
74
|
+
const capabilities = [
|
|
75
|
+
'infra.up',
|
|
76
|
+
'templates.list',
|
|
77
|
+
'board.web.import',
|
|
78
|
+
'contracts.cli',
|
|
79
|
+
] as const satisfies readonly AnkhCapabilityId[];
|
|
80
|
+
|
|
81
|
+
expect(capabilities).toEqual([
|
|
82
|
+
'infra.up',
|
|
83
|
+
'templates.list',
|
|
84
|
+
'board.web.import',
|
|
85
|
+
'contracts.cli',
|
|
86
|
+
]);
|
|
87
|
+
});
|
|
88
|
+
});
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export type AnkhCommandCategory = string;
|
|
2
|
+
|
|
3
|
+
export type AnkhProviderReference = `./${string}`;
|
|
4
|
+
|
|
5
|
+
export type AnkhCapabilityId = `${string}.${string}`;
|
|
6
|
+
|
|
7
|
+
export interface AnkhCommandDescriptor {
|
|
8
|
+
readonly path: readonly [string, ...string[]];
|
|
9
|
+
readonly summary: string;
|
|
10
|
+
readonly capability: AnkhCapabilityId;
|
|
11
|
+
readonly aliases?: readonly string[];
|
|
12
|
+
readonly examples?: readonly string[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface AnkhCommandProviderManifest {
|
|
16
|
+
readonly id: string;
|
|
17
|
+
readonly category: AnkhCommandCategory;
|
|
18
|
+
readonly version: string;
|
|
19
|
+
readonly capabilities: readonly AnkhCapabilityId[];
|
|
20
|
+
readonly commands: readonly AnkhCommandDescriptor[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface AnkhPackageMetadata {
|
|
24
|
+
readonly category: AnkhCommandCategory;
|
|
25
|
+
readonly provider: AnkhProviderReference | null;
|
|
26
|
+
readonly capabilities: readonly AnkhCapabilityId[];
|
|
27
|
+
}
|
package/src/contracts.test.ts
CHANGED
|
@@ -56,6 +56,17 @@ async function collectTypeScriptFiles(directory: string): Promise<string[]> {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
describe('contracts', () => {
|
|
59
|
+
it('exports the cli subpath for Ankh discovery contracts', async () => {
|
|
60
|
+
const packageJson = JSON.parse(await readFile(join(process.cwd(), 'package.json'), 'utf8')) as {
|
|
61
|
+
exports?: Record<string, { default?: string; types?: string }>;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
expect(packageJson.exports?.['./cli']).toEqual({
|
|
65
|
+
types: './dist/cli.d.ts',
|
|
66
|
+
default: './dist/cli.js',
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
59
70
|
it('exports stable platform constants', () => {
|
|
60
71
|
expect(NAVIGATOR_TYPES).toEqual(['stack', 'tabs', 'drawer']);
|
|
61
72
|
expect(APP_CATEGORIES).toEqual([
|
|
@@ -213,7 +224,7 @@ describe('contracts', () => {
|
|
|
213
224
|
|
|
214
225
|
it('ThemeModeConfig.harmony accepts all ColorHarmony values', () => {
|
|
215
226
|
for (const harmony of COLOR_HARMONIES) {
|
|
216
|
-
const config
|
|
227
|
+
const config = { primaryColor: '#ff0000', harmony } satisfies ThemeModeConfig;
|
|
217
228
|
expect(config.harmony).toBe(harmony);
|
|
218
229
|
}
|
|
219
230
|
});
|