@hyperscale0/hsx 1.0.130 → 1.0.134

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.
@@ -1 +1 @@
1
- {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../src/compile.ts"],"names":[],"mappings":"AAOA,OAAO,EAAwB,KAAK,eAAe,EAAE,MAAM,WAAW,CAAC;AACvE,OAAO,EAgBL,KAAK,WAAW,EAQjB,MAAM,kBAAkB,CAAC;AAU1B,OAAO,EAIL,KAAK,UAAU,EAKf,KAAK,IAAI,EACV,MAAM,UAAU,CAAC;AAClB,OAAO,EAA0B,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEhF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAExD,MAAM,WAAW,iBAAkB,SAAQ,UAAU;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;CACpC;AACD,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,IAAI,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9C,aAAa,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3E;AACD,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,eAAe,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;CACnB;AACD,MAAM,WAAW,cAAc;IAC7B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAAC;CAClE;AACD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7B,WAAW,EAAE,iBAAiB,EAAE,CAAC;IACjC,SAAS,CAAC,EAAE;QACV,QAAQ,EAAE,WAAW,CAAC;QACtB,YAAY,EAAE,eAAe,CAAC;QAC9B,SAAS,EAAE,qBAAqB,EAAE,CAAC;KACpC,CAAC;CACH;AAqTD,wBAAgB,OAAO,CACrB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,cAAmB,GAC3B,aAAa,CA6zHf"}
1
+ {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../src/compile.ts"],"names":[],"mappings":"AAOA,OAAO,EAAwB,KAAK,eAAe,EAAE,MAAM,WAAW,CAAC;AACvE,OAAO,EAgBL,KAAK,WAAW,EAQjB,MAAM,kBAAkB,CAAC;AAU1B,OAAO,EAIL,KAAK,UAAU,EAKf,KAAK,IAAI,EACV,MAAM,UAAU,CAAC;AAClB,OAAO,EAA0B,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEhF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAExD,MAAM,WAAW,iBAAkB,SAAQ,UAAU;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;CACpC;AACD,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,IAAI,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9C,aAAa,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3E;AACD,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,eAAe,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;CACnB;AACD,MAAM,WAAW,cAAc;IAC7B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAAC;CAClE;AACD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7B,WAAW,EAAE,iBAAiB,EAAE,CAAC;IACjC,SAAS,CAAC,EAAE;QACV,QAAQ,EAAE,WAAW,CAAC;QACtB,YAAY,EAAE,eAAe,CAAC;QAC9B,SAAS,EAAE,qBAAqB,EAAE,CAAC;KACpC,CAAC;CACH;AAqTD,wBAAgB,OAAO,CACrB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,cAAmB,GAC3B,aAAa,CAo5Hf"}
@@ -285,6 +285,9 @@ export function compile(source, options = {}) {
285
285
  const declarationSources = new Map();
286
286
  const standardOrigins = new Map();
287
287
  const requirementOrigins = new Map();
288
+ // Instruments that lost a std action to an empty all() parent. Their
289
+ // lifecycles drop the states only that action reached.
290
+ const trimmed = new Set();
288
291
  const used = new Set();
289
292
  for (const use of program.decls.filter((d) => d.kind === "use")) {
290
293
  if (used.has(use.name))
@@ -366,6 +369,11 @@ export function compile(source, options = {}) {
366
369
  const assignments = new Map();
367
370
  const attachmentSubjects = new Map();
368
371
  const names = new Set();
372
+ // A record's create turns public only through a program-level expose,
373
+ // which applies after lowering, so creation input needs the list first.
374
+ const exposedCreates = new Set(program.decls.flatMap((decl) => decl.kind === "expose" && decl.target.endsWith(".create")
375
+ ? [decl.target.split(".").slice(0, -1).join("_")]
376
+ : []));
369
377
  for (const decl of program.decls) {
370
378
  if (decl.kind === "expose" || decl.kind === "hide" || decl.kind === "use")
371
379
  continue;
@@ -2019,6 +2027,14 @@ export function compile(source, options = {}) {
2019
2027
  })
2020
2028
  : undefined;
2021
2029
  const charges = vat ? [charge, vat] : [charge];
2030
+ // A payer's limit reads this: a buyer pays the charges on
2031
+ // top, a seller pays them out of the amount.
2032
+ derived("debit", "Payer debit", {
2033
+ op: "sum",
2034
+ values: paidBy === "buyer"
2035
+ ? [transfer.amount, ...charges]
2036
+ : [transfer.amount],
2037
+ });
2022
2038
  const net = paidBy === "seller"
2023
2039
  ? derived("net", "Amount after fee", {
2024
2040
  op: "subtract",
@@ -2085,7 +2101,7 @@ export function compile(source, options = {}) {
2085
2101
  }
2086
2102
  if (actionFeeCalculations.length)
2087
2103
  a.calculate = [...(a.calculate ?? []), ...actionFeeCalculations];
2088
- if (attachmentInfo && !attachmentInfo.child) {
2104
+ if (attachmentInfo) {
2089
2105
  if (attachmentInfo.exposed.has(name)) {
2090
2106
  if (automatic(a.actor))
2091
2107
  fail(row, `${name} runs on the clock or its parent, not a caller`, "expose only caller actions");
@@ -2139,6 +2155,11 @@ export function compile(source, options = {}) {
2139
2155
  message: `${id}.${name}.subject.${requirement.field.name}`,
2140
2156
  });
2141
2157
  }
2158
+ // A parent list may name a list parameter such as `[parent, on]`.
2159
+ if (typeof a.actor === "object" &&
2160
+ "parent" in a.actor &&
2161
+ Array.isArray(a.actor.parent))
2162
+ a.actor.parent = a.actor.parent.flat();
2142
2163
  // A parent actor over an empty all() names no instrument that could
2143
2164
  // invoke the action. A std action then does not exist in this program;
2144
2165
  // in user code the all() is a mistake.
@@ -2151,6 +2172,7 @@ export function compile(source, options = {}) {
2151
2172
  fail(parent ?? row, `${parent?.kind === "call" ? `${parent.name}(${text(parent.args[0])})` : `the parent actor of ${name}`} matches no instrument`, "name an instrument this program declares or attaches");
2152
2173
  }
2153
2174
  delete lifecycle.transitions[name];
2175
+ trimmed.add(id);
2154
2176
  continue;
2155
2177
  }
2156
2178
  inst.actions[name] = a;
@@ -2363,8 +2385,7 @@ export function compile(source, options = {}) {
2363
2385
  const attachedInst = document.instruments.find((i) => i.id === instId);
2364
2386
  for (const createdInst of document.instruments
2365
2387
  .slice(firstAttachedInstrument)
2366
- .filter((instrument) => instrument.id === instId ||
2367
- instrument.actions.create?.publicAction)) {
2388
+ .filter((instrument) => instrument.id === instId || exposedCreates.has(instrument.id))) {
2368
2389
  if (!createdInst.actions.create)
2369
2390
  continue;
2370
2391
  const owned = new Set(createdInst.calculate.map((node) => node.target));
@@ -2377,8 +2398,14 @@ export function compile(source, options = {}) {
2377
2398
  }
2378
2399
  const create = createdInst.actions.create;
2379
2400
  for (const field of createdInst.fields) {
2401
+ // The engine resolves a lone candidate itself; with several (a
2402
+ // plan's slices) the caller names one, as late_charge does.
2403
+ if (field.type === "ref" && field.targetKind === "instrument") {
2404
+ if (!create.input.some((input) => input.name === field.name))
2405
+ create.input.push({ ...field, optional: true });
2406
+ continue;
2407
+ }
2380
2408
  if (field.type === "account" ||
2381
- (field.type === "ref" && field.targetKind === "instrument") ||
2382
2409
  (field.type === "list" &&
2383
2410
  field.item === "ref" &&
2384
2411
  field.targetKind === "instrument") ||
@@ -2387,18 +2414,22 @@ export function compile(source, options = {}) {
2387
2414
  owned.has(field.name) ||
2388
2415
  create.input.some((input) => input.name === field.name))
2389
2416
  continue;
2390
- create.subject ??= { requirements: [], adapters: [] };
2391
- const existing = create.subject.requirements.find((item) => item.field.name === field.name);
2417
+ const existing = create.subject?.requirements.find((item) => item.field.name === field.name);
2392
2418
  if (existing) {
2393
2419
  if (canonicalJson(existing.field) !== canonicalJson(field))
2394
2420
  failWithCode(entry, "subject_field_conflict", `${createdInst.id}.create.subject.${field.name} conflicts with its instrument field`, "use the instrument field's type and constraints");
2395
2421
  continue;
2396
2422
  }
2423
+ // A creation value belongs to this agreement. Only a rename shares
2424
+ // it as object metadata; a matching authored field name does not,
2425
+ // so two agreements never read each other's amount.
2397
2426
  const objectField = renames.get(field.name);
2398
- const requirement = {
2399
- field,
2400
- ...(objectField ? { objectField } : {}),
2401
- };
2427
+ if (!objectField) {
2428
+ create.input.push({ ...field });
2429
+ continue;
2430
+ }
2431
+ const requirement = { field, objectField };
2432
+ create.subject ??= { requirements: [], adapters: [] };
2402
2433
  create.subject.requirements.push(requirement);
2403
2434
  requirementOrigins.set(requirement, {
2404
2435
  source: declarationSources.get(template) ?? "program",
@@ -2412,6 +2443,12 @@ export function compile(source, options = {}) {
2412
2443
  Object.values(attachedInst.actions).some((action) => action.subject?.requirements.some((requirement) => requirement.field.name === oldName));
2413
2444
  if (!found) {
2414
2445
  const renameEntry = renameEntries.get(oldName) ?? entry;
2446
+ const record = document.instruments
2447
+ .slice(firstAttachedInstrument)
2448
+ .find((instrument) => instrument.id.startsWith(`${instId}_`) &&
2449
+ instrument.fields.some((field) => field.name === oldName));
2450
+ if (record)
2451
+ failWithCode(renameEntry, "subject_field_unknown", `rename source '${oldName}' belongs to the ${record.id.slice(instId.length + 1)} record of ${targetTemplate}; rename binds only fields of ${targetTemplate} itself`, `remove this rename; supply ${oldName} as input when the record is created, or set it as a tunable where the header offers one`);
2415
2452
  const declared = attachedInst
2416
2453
  ? Object.values(attachedInst.actions).flatMap((action) => action.subject?.requirements.map((requirement) => requirement.field.name) ?? [])
2417
2454
  : [];
@@ -2796,9 +2833,19 @@ export function compile(source, options = {}) {
2796
2833
  return !candidates.every((candidate) => !targets.includes(candidate) &&
2797
2834
  targets.some((target) => kin(target, candidate)));
2798
2835
  });
2799
- // A count over no matchable member is zero.
2836
+ // A count over no matchable member is zero, in a requirement or a calculation.
2800
2837
  for (const inst of document.instruments)
2801
- for (const action of Object.values(inst.actions))
2838
+ for (const action of Object.values(inst.actions)) {
2839
+ if (action.calculate)
2840
+ action.calculate = action.calculate.map((calculation) => calculation.op === "aggregate" &&
2841
+ calculation.measure === "count" &&
2842
+ !matchable(calculation.selection, inst, action).length
2843
+ ? {
2844
+ target: calculation.target,
2845
+ op: "sum",
2846
+ values: [{ literal: 0 }],
2847
+ }
2848
+ : calculation);
2802
2849
  action.requires = action.requires.map((requirement) => requirement.kind === "aggregate" &&
2803
2850
  requirement.measure === "count" &&
2804
2851
  !matchable(requirement.selection, inst, action).length
@@ -2809,6 +2856,7 @@ export function compile(source, options = {}) {
2809
2856
  right: requirement.value,
2810
2857
  }
2811
2858
  : requirement);
2859
+ }
2812
2860
  const checkSelection = (selection, at, scope) => {
2813
2861
  walk(selection.overlaps, "overlaps", site(selection, "overlaps", at), scope);
2814
2862
  walk(selection.anchor, "anchor", site(selection, "anchor", at), scope);
@@ -2932,7 +2980,7 @@ export function compile(source, options = {}) {
2932
2980
  (edge.to !== "preserve" &&
2933
2981
  !inst.lifecycle.states.includes(edge.to))))
2934
2982
  continue;
2935
- let specialized = false;
2983
+ let specialized = trimmed.has(inst.id);
2936
2984
  for (const [key, action] of Object.entries(inst.actions)) {
2937
2985
  const constant = (value) => {
2938
2986
  if ("literal" in value)
@@ -3018,6 +3066,22 @@ export function compile(source, options = {}) {
3018
3066
  if (Object.values(instrument.actions).filter((action) => action.publicAction === decl.name).length > 1)
3019
3067
  fail(decl, `public action ${decl.name} is used more than once on ${parts.join(".")}`, "give each exposed action a distinct public name");
3020
3068
  }
3069
+ // A public action on a fresh attachment creates it first with no input
3070
+ // (in the engine executor), so creation that needs input must be public.
3071
+ for (const kind of document.objects)
3072
+ for (const attachment of kind.attachments) {
3073
+ if (attachment.parent)
3074
+ continue;
3075
+ const instrument = byId.get(attachment.instrument);
3076
+ const create = instrument.actions.create;
3077
+ const needed = create?.input.filter((field) => !field.optional) ?? [];
3078
+ const entry = Object.values(instrument.actions).find((action) => action.publicAction);
3079
+ if (!needed.length || create.publicAction || !entry)
3080
+ continue;
3081
+ fail(objects
3082
+ .get(kind.id)
3083
+ .body.entries.find((row) => new RegExp(`^attach\\s+${attachment.name}\\s*=`).test(row.key)) ?? objects.get(kind.id), `${attachment.name} starts from ${entry.publicAction}, but its create needs ${needed.map((field) => field.name).join(", ")} and is not exposed`, `expose create on ${attachment.name} so the caller supplies ${needed.length === 1 ? "it" : "them"}, or rename { ${needed[0].name}: ${needed[0].name} } to read object metadata`);
3084
+ }
3021
3085
  for (const kind of document.objects) {
3022
3086
  for (const name of kind.entryActions ?? []) {
3023
3087
  const eligible = kind.attachments.some((attachment) => {