@mdbase-dev/connect-dev 0.1.0-beta.124 → 0.1.0-beta.125

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 CHANGED
@@ -79,6 +79,28 @@ The helper validates each contract document and derives the exact semantic
79
79
  `provides` descriptors. Managed resources evolve with the pack; seed resources
80
80
  become collection-owned after their initial creation.
81
81
 
82
+ A seed type may list the exact starters previously shipped for it, so a
83
+ collection that still has any of them can be upgraded:
84
+
85
+ ```ts
86
+ {
87
+ kind: "type",
88
+ mode: "seed",
89
+ source: "types/task/3.md",
90
+ target: "_types/task.md",
91
+ document: taskV3,
92
+ upgradeFrom: [{ document: taskV1 }, { document: taskV2 }]
93
+ }
94
+ ```
95
+
96
+ `defineTypePack` emits these as `upgrade_from` baselines, computing each
97
+ digest and copying the `version` the document declares (an explicit `version`
98
+ must match it). It rejects baselines on anything but a seed type, duplicates,
99
+ the resource's own document, and documents of a different type kind or name,
100
+ using the same validator as application manifests. An unedited starter is
101
+ replaced exactly; an edited one is merged only against the baseline the
102
+ collection's lock records as its origin, and is otherwise left unchanged.
103
+
82
104
  Native applications may add a reverse-domain private-use callback scheme that
83
105
  matches the v1 manifest's application ID, such as
84
106
  `example.tasks.desktop://auth/mdbase/callback` for
package/dist/index.d.ts CHANGED
@@ -40,6 +40,15 @@ export interface TypePackResourceInput {
40
40
  target?: string;
41
41
  /** Exact UTF-8 resource document included in the provision. */
42
42
  document: string;
43
+ /**
44
+ * Seed types only: the exact starters previously shipped for this resource
45
+ * that a collection may be upgraded from, oldest first. Digests are computed
46
+ * from each document, and `version` defaults to the one the document declares.
47
+ */
48
+ upgradeFrom?: Array<{
49
+ document: string;
50
+ version?: number;
51
+ }>;
43
52
  }
44
53
  export interface TypePackDefinition {
45
54
  id: string;
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { Ajv2020 } from "ajv/dist/2020.js";
3
- import { parseDocument } from "yaml";
3
+ import { isMap, parseDocument } from "yaml";
4
4
  import { connectError, MdbaseCollectionClient } from "@mdbase-dev/connect/advanced";
5
- import { formatManifestValidationIssues, validateAppManifest } from "@mdbase-dev/connect-protocol/manifest";
5
+ import { formatManifestValidationIssues, validateAppManifest, validateTypePackProvision } from "@mdbase-dev/connect-protocol/manifest";
6
6
  import connectProblemSchema from "@mdbase-dev/connect-protocol/schemas/connect-problem.v1.schema.json" with { type: "json" };
7
7
  import dataContractSchema from "@mdbase-dev/connect-protocol/schemas/data-contract.schema.json" with { type: "json" };
8
8
  import connectProtocolSchema from "@mdbase-dev/connect-protocol/schemas/connect-protocol.v1.schema.json" with { type: "json" };
@@ -69,12 +69,13 @@ export function defineTypePack(definition) {
69
69
  version: definition.version,
70
70
  ...(definition.name ? { name: definition.name } : {}),
71
71
  ...(definition.description ? { description: definition.description } : {}),
72
- resources: definition.resources.map(({ kind, mode, source, target = source, document }) => ({
72
+ resources: definition.resources.map(({ kind, mode, source, target = source, document, upgradeFrom }) => ({
73
+ ...(upgradeFrom ? { upgrade_from: upgradeFrom.map(upgradeBaseline) } : {}),
73
74
  kind,
74
75
  mode,
75
76
  source,
76
77
  target,
77
- digest: `sha256:${createHash("sha256").update(document).digest("hex")}`
78
+ digest: sha256(document)
78
79
  }))
79
80
  },
80
81
  resources: definition.resources.map(({ source, document }) => ({ source, document })),
@@ -83,8 +84,28 @@ export function defineTypePack(definition) {
83
84
  const result = validateProtocolValue(provision, "typePackProvision");
84
85
  if (!result.valid)
85
86
  throw new TypePackDefinitionError(result.issues);
87
+ const issues = validateTypePackProvision(provision);
88
+ if (issues.length > 0)
89
+ throw new TypePackDefinitionError(issues);
86
90
  return provision;
87
91
  }
92
+ function upgradeBaseline({ document, version }) {
93
+ const declared = version ?? declaredTypeVersion(document);
94
+ return { digest: sha256(document), document, ...(declared === undefined ? {} : { version: declared }) };
95
+ }
96
+ /** The positive integer `version` a type document declares, if any. */
97
+ function declaredTypeVersion(document) {
98
+ const frontmatter = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/u.exec(document)?.[1];
99
+ const parsed = frontmatter === undefined ? undefined : parseDocument(frontmatter, { uniqueKeys: true });
100
+ if (!parsed || parsed.errors.length > 0 || !isMap(parsed.contents))
101
+ return undefined;
102
+ // Read only `version`, so anchors elsewhere in a starter need no alias expansion.
103
+ const version = parsed.get("version");
104
+ return Number.isInteger(version) && Number(version) > 0 ? Number(version) : undefined;
105
+ }
106
+ function sha256(document) {
107
+ return `sha256:${createHash("sha256").update(document).digest("hex")}`;
108
+ }
88
109
  function exactContractReferenceFromDocument(document, resourceIndex) {
89
110
  const frontmatter = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/u.exec(document)?.[1];
90
111
  if (frontmatter === undefined) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mdbase-dev/connect-dev",
3
- "version": "0.1.0-beta.124",
3
+ "version": "0.1.0-beta.125",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -26,8 +26,8 @@
26
26
  "dependencies": {
27
27
  "ajv": "^8.20.0",
28
28
  "yaml": "^2.9.1",
29
- "@mdbase-dev/connect": "0.1.0-beta.124",
30
- "@mdbase-dev/connect-protocol": "0.1.0-beta.124"
29
+ "@mdbase-dev/connect": "0.1.0-beta.125",
30
+ "@mdbase-dev/connect-protocol": "0.1.0-beta.125"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/node": "^24.0.0",
@@ -36,7 +36,7 @@
36
36
  },
37
37
  "scripts": {
38
38
  "build": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.json && node -e \"require('node:fs').chmodSync('dist/cli.js',0o755)\"",
39
- "test": "vitest run",
39
+ "test": "node ../../scripts/ci/vitest.mjs",
40
40
  "typecheck": "tsc -p tsconfig.json --noEmit"
41
41
  }
42
42
  }