acrylblends 1.2.0 → 1.3.1
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/index.d.ts +2 -1
- package/dist/index.js +44 -10
- package/dist/index.js.map +1 -1
- package/docs/framework/guides/create-acrylblends.md +4 -2
- package/docs/framework/workshop/README.md +4 -2
- package/docs/framework/workshop/facilitator.md +1 -1
- package/lib/cordis/door.d.ts +54 -2
- package/lib/cordis/door.js +131 -4
- package/package.json +1 -1
- package/plugins/acryl-door/plugin.json +3 -0
- package/plugins/acryl-door/src/cli/acryl.ts +63 -6
- package/plugins/acryl-door/src/host/door.ts +91 -5
- package/plugins/acryl-door/src/host/operator-routes.ts +21 -1
- package/plugins/acryl-door/src/host/verbs.ts +11 -1
- package/plugins/acryl-door/src/index.ts +2 -1
- package/plugins/builder/index.ts +13 -35
- package/plugins/builder/plugin.json +4 -2
- package/plugins/extensions/index.ts +78 -19
- package/plugins/extensions/plugin-store.ts +27 -0
- package/plugins/extensions/plugin.json +1 -1
- package/plugins/extensions/routes.ts +92 -0
- package/plugins/extensions/stage.ts +15 -5
- package/plugins/home/index.ts +3 -1
- package/plugins/manifest/plugin.json +1 -1
- package/plugins/plugin-share/README.md +66 -0
- package/plugins/plugin-share/index.ts +581 -0
- package/plugins/plugin-share/package.ts +186 -0
- package/plugins/plugin-share/plugin.json +15 -0
- package/plugins/plugin-share/publish.ts +65 -0
- package/plugins/plugin-share/pull-check.ts +129 -0
- package/plugins/plugin-share/pulled-records.ts +70 -0
- package/templates/agent/.gitattributes +2 -0
- package/templates/agent/blend.yaml +2 -0
- package/templates/agent/src/app.ts +6 -0
- package/templates/agent/template.json +1 -0
- package/templates/blank/.gitattributes +2 -0
- package/templates/blank/blend.yaml +3 -0
- package/templates/blank/src/app.ts +8 -0
- package/templates/blank/template.json +1 -0
- package/templates/chat/.gitattributes +2 -0
- package/templates/chat/blend.yaml +3 -0
- package/templates/chat/src/app.ts +8 -0
- package/templates/chat/template.json +1 -0
- package/templates/nodejs/.gitattributes +2 -0
- package/templates/nodejs/blend.yaml +3 -0
- package/templates/nodejs/src/app.ts +8 -0
- package/templates/nodejs/template.json +1 -0
- package/templates/notes/.gitattributes +2 -0
- package/templates/notes/blend.yaml +3 -0
- package/templates/notes/src/app.ts +8 -0
- package/templates/notes/template.json +1 -0
- package/templates/todo/.gitattributes +2 -0
package/dist/index.d.ts
CHANGED
|
@@ -187,7 +187,8 @@ export declare function assertTargetFree(target: string): void;
|
|
|
187
187
|
export declare function copyTemplate(source: string, target: string, name: string): string[];
|
|
188
188
|
export declare function readTemplatePlugins(templateDir: string): string[];
|
|
189
189
|
/**
|
|
190
|
-
* Add run-time dependencies to an app's package.json
|
|
190
|
+
* Add run-time dependencies to an app's package.json and sort the keys. Returns the names to install: those added, and those moved because a plugin asks for a newer
|
|
191
|
+
* version than the app lists (the plugin's new code needs it). A version the app lists that is the same or newer stays. A package the app lists as a development
|
|
191
192
|
* dependency too is taken out of that list: npm lets the development entry win, so `npm install --omit=dev` would leave a run-time dependency out.
|
|
192
193
|
*/
|
|
193
194
|
export declare function mergeDependencies(appDir: string, dependencies: Readonly<Record<string, string>>): string[];
|
package/dist/index.js
CHANGED
|
@@ -74,7 +74,7 @@ var packages = {
|
|
|
74
74
|
},
|
|
75
75
|
"acryl-blends-frame": {
|
|
76
76
|
"name": "blends-frame",
|
|
77
|
-
"version": "0.1.
|
|
77
|
+
"version": "0.1.1"
|
|
78
78
|
}
|
|
79
79
|
};
|
|
80
80
|
//#endregion
|
|
@@ -1002,6 +1002,18 @@ function applyIdeProfile(root, input) {
|
|
|
1002
1002
|
//#region src/version.ts
|
|
1003
1003
|
/** The version of this package. */
|
|
1004
1004
|
const VERSION = createRequire(import.meta.url)("../package.json").version;
|
|
1005
|
+
/** Semver order for the release versions (numeric segments; a pre-release sorts before its release). */
|
|
1006
|
+
function compareVersions(a, b) {
|
|
1007
|
+
const pa = a.split(/[.-]/u).map((part) => Number.isNaN(Number(part)) ? part : Number(part));
|
|
1008
|
+
const pb = b.split(/[.-]/u).map((part) => Number.isNaN(Number(part)) ? part : Number(part));
|
|
1009
|
+
for (let i = 0; i < Math.max(pa.length, pb.length); i += 1) {
|
|
1010
|
+
const x = pa[i] ?? 0;
|
|
1011
|
+
const y = pb[i] ?? 0;
|
|
1012
|
+
if (x < y) return -1;
|
|
1013
|
+
if (x > y) return 1;
|
|
1014
|
+
}
|
|
1015
|
+
return 0;
|
|
1016
|
+
}
|
|
1005
1017
|
/** The DSH release the frame's packages pin as peers, so an app's DSH pin is the same one. */
|
|
1006
1018
|
const FRAME_DSH_VERSION = dshVersion;
|
|
1007
1019
|
/** Every package the frame publishes, in the file's order. */
|
|
@@ -1151,6 +1163,11 @@ const HOST_PROVIDED_IDS = /* @__PURE__ */ new Set([
|
|
|
1151
1163
|
"save",
|
|
1152
1164
|
"acryl-door"
|
|
1153
1165
|
]);
|
|
1166
|
+
/**
|
|
1167
|
+
* Services the app's rows provide that the host's own rows call: the door and the frame reach `pluginShare`, and no host row provides that name. Left out of
|
|
1168
|
+
* the isolate list, so they find it; every other service stays in the app's realm.
|
|
1169
|
+
*/
|
|
1170
|
+
const REACHED_FROM_HOST = /* @__PURE__ */ new Set(["pluginShare"]);
|
|
1154
1171
|
/** The generated `frame/app-plugins.mjs`, by the row that mounts it. */
|
|
1155
1172
|
const APP_PLUGINS_FILE = "frame/app-plugins.mjs";
|
|
1156
1173
|
/**
|
|
@@ -1176,12 +1193,14 @@ function appPluginsRow(prefix) {
|
|
|
1176
1193
|
" return path === base || path.startsWith(base + '/') ? path : base + (path.startsWith('/') ? '' : '/') + path",
|
|
1177
1194
|
"}",
|
|
1178
1195
|
"",
|
|
1179
|
-
"/** The router as the app's rows see it: mounts land under the prefix, every other member is the host router's. */",
|
|
1196
|
+
"/** The router as the app's rows see it: mounts land under the prefix, and a plugin's own request (its install check) finds them there; every other member is the host router's. */",
|
|
1180
1197
|
"function appRouter(router, prefix) {",
|
|
1181
1198
|
" const route = (path, app) => router.route(prefixedAppRoute(prefix, path), app)",
|
|
1199
|
+
" const request = (input, ...rest) => router.request(typeof input === 'string' && input.startsWith('/') ? prefixedAppRoute(prefix, input) : input, ...rest)",
|
|
1182
1200
|
" return new Proxy(router, {",
|
|
1183
1201
|
" get(target, property) {",
|
|
1184
1202
|
" if (property === 'route') return route",
|
|
1203
|
+
" if (property === 'request') return request",
|
|
1185
1204
|
" const value = Reflect.get(target, property, target)",
|
|
1186
1205
|
" return typeof value === 'function' ? value.bind(target) : value",
|
|
1187
1206
|
" },",
|
|
@@ -1190,8 +1209,10 @@ function appPluginsRow(prefix) {
|
|
|
1190
1209
|
"",
|
|
1191
1210
|
"export async function apply(ctx, config) {",
|
|
1192
1211
|
` const prefix = typeof config?.appPrefix === 'string' ? config.appPrefix : ${JSON.stringify(prefix)}`,
|
|
1193
|
-
" // The rows read ctx.router as the app's own router: the same paths as on their own server, under the frame's prefix.",
|
|
1194
|
-
"
|
|
1212
|
+
" // The rows read ctx.router as the app's own router: the same paths as on their own server, under the frame's prefix. A getter, read by each plugin",
|
|
1213
|
+
" // from its own context: it gets the host router traced for that context, so a route it mounts is its own and goes when the plugin is removed",
|
|
1214
|
+
" // (a router taken once here would make every route this row's, served until the whole app reloads).",
|
|
1215
|
+
" const appScope = ctx.extend({ get router() { return appRouter(this.get('router'), prefix) } })",
|
|
1195
1216
|
" const fibers = await composeInto(appScope, ctx.appInstance, { host: true })",
|
|
1196
1217
|
" ctx.effect(() => () => { for (const fiber of [...fibers].reverse()) void fiber.dispose() }, 'app-plugins: dispose')",
|
|
1197
1218
|
"}",
|
|
@@ -1229,7 +1250,7 @@ function providedServices(appDir) {
|
|
|
1229
1250
|
}
|
|
1230
1251
|
};
|
|
1231
1252
|
for (const row of ownRowIds(appDir)) walk(join(appDir, "plugins", row));
|
|
1232
|
-
return Object.fromEntries([...provided].sort().map((name) => [name, true]));
|
|
1253
|
+
return Object.fromEntries([...provided].filter((name) => !REACHED_FROM_HOST.has(name)).sort().map((name) => [name, true]));
|
|
1233
1254
|
}
|
|
1234
1255
|
/**
|
|
1235
1256
|
* The frame rows for an app: its routes row when it carries `src/frame.ts`, and the composition row when its `src/app.ts` exports `composeInto`.
|
|
@@ -1662,8 +1683,19 @@ function readTemplatePlugins(templateDir) {
|
|
|
1662
1683
|
const { plugins } = JSON.parse(readFileSync(file, "utf8"));
|
|
1663
1684
|
return plugins ?? [];
|
|
1664
1685
|
}
|
|
1686
|
+
/** A version a plugin's pin can be compared with: an exact one or a caret or tilde range. A tag, a path or a URL is the app's own choice. */
|
|
1687
|
+
function comparableVersion(spec) {
|
|
1688
|
+
return /^[\^~]?\d+\.\d+\.\d+(?:-[\w.]+)?$/u.test(spec) ? spec.replace(/^[\^~]/u, "") : void 0;
|
|
1689
|
+
}
|
|
1690
|
+
/** Whether a plugin's pin asks for more than what the app has: the plugin's code was written against that version. */
|
|
1691
|
+
function asksForNewer(wanted, current) {
|
|
1692
|
+
const a = comparableVersion(wanted);
|
|
1693
|
+
const b = comparableVersion(current);
|
|
1694
|
+
return a !== void 0 && b !== void 0 && compareVersions(a, b) > 0;
|
|
1695
|
+
}
|
|
1665
1696
|
/**
|
|
1666
|
-
* Add run-time dependencies to an app's package.json
|
|
1697
|
+
* Add run-time dependencies to an app's package.json and sort the keys. Returns the names to install: those added, and those moved because a plugin asks for a newer
|
|
1698
|
+
* version than the app lists (the plugin's new code needs it). A version the app lists that is the same or newer stays. A package the app lists as a development
|
|
1667
1699
|
* dependency too is taken out of that list: npm lets the development entry win, so `npm install --omit=dev` would leave a run-time dependency out.
|
|
1668
1700
|
*/
|
|
1669
1701
|
function mergeDependencies(appDir, dependencies) {
|
|
@@ -1671,14 +1703,16 @@ function mergeDependencies(appDir, dependencies) {
|
|
|
1671
1703
|
const manifest = JSON.parse(readFileSync(file, "utf8"));
|
|
1672
1704
|
const current = manifest.dependencies ?? {};
|
|
1673
1705
|
const added = Object.keys(dependencies).filter((name) => !(name in current));
|
|
1706
|
+
const moved = Object.entries(dependencies).filter(([name, wanted]) => current[name] !== void 0 && asksForNewer(wanted, current[name]));
|
|
1674
1707
|
const merged = {
|
|
1675
1708
|
...dependencies,
|
|
1676
|
-
...current
|
|
1709
|
+
...current,
|
|
1710
|
+
...Object.fromEntries(moved)
|
|
1677
1711
|
};
|
|
1678
1712
|
manifest.dependencies = Object.fromEntries(Object.entries(merged).sort(([a], [b]) => a.localeCompare(b)));
|
|
1679
1713
|
if (manifest.devDependencies !== void 0) manifest.devDependencies = Object.fromEntries(Object.entries(manifest.devDependencies).filter(([name]) => !(name in merged)));
|
|
1680
1714
|
writeFileSync(file, `${JSON.stringify(manifest, null, 2)}\n`);
|
|
1681
|
-
return added;
|
|
1715
|
+
return [...added, ...moved.map(([name]) => name)];
|
|
1682
1716
|
}
|
|
1683
1717
|
/** Add `package.json` "imports" entries (`#acryl-kv`: `./plugins/acryl-kv/src/index.ts`); an entry the app already has is kept. Returns the names added. */
|
|
1684
1718
|
function mergeImports(appDir, imports, pluginsDir) {
|
|
@@ -2142,7 +2176,7 @@ async function add(options, io) {
|
|
|
2142
2176
|
if (refused !== 0) return refused;
|
|
2143
2177
|
}
|
|
2144
2178
|
io.stdout.write(`added ${toCopy.map((plugin) => plugin.name).join(", ")} to ${appDir}\n`);
|
|
2145
|
-
if (addedDependencies.length > 0) io.stdout.write(`
|
|
2179
|
+
if (addedDependencies.length > 0) io.stdout.write(`dependencies to install: ${addedDependencies.join(", ")} (run npm install)\n`);
|
|
2146
2180
|
for (const plugin of toCopy.filter((plugin) => names.includes(plugin.name))) {
|
|
2147
2181
|
const mounted = MOUNTED.find((candidate) => candidate.name === plugin.name);
|
|
2148
2182
|
const result = mounted ? mount(appDir, mounted) : void 0;
|
|
@@ -3765,7 +3799,7 @@ async function upgrade(options, io) {
|
|
|
3765
3799
|
const upgradedPlugins = plans.filter((p) => [...p.files.values()].some((s) => s !== "same" && s !== "extra") || p.isNew).map((p) => p.plugin.name);
|
|
3766
3800
|
io.stdout.write(`\nupgraded ${[...upgradedPlugins, ...frameChanged ? ["the frame"] : []].join(", ")}\n`);
|
|
3767
3801
|
if (conflicts + frameBackups > 0) io.stdout.write(`the ${conflicts + frameBackups} edited file(s) replaced by --force are saved in ${posix$1(relative(appDir, backup))}/\n`);
|
|
3768
|
-
io.stdout.write(`acrylblends is now ^${VERSION} in package.json${addedDependencies.length > 0 ? `;
|
|
3802
|
+
io.stdout.write(`acrylblends is now ^${VERSION} in package.json${addedDependencies.length > 0 ? `; dependencies to install: ${[...new Set(addedDependencies)].join(", ")}` : ""}: run npm install, then npm run check and npm test\n`);
|
|
3769
3803
|
return 0;
|
|
3770
3804
|
} finally {
|
|
3771
3805
|
rmSync(scratch, {
|