@techspokes/typescript-wsdl-client 1.1.8 → 1.3.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.
Files changed (85) hide show
  1. package/README.md +22 -3
  2. package/dist/checkedPlanning.js +27 -4
  3. package/dist/cli.js +17 -1
  4. package/dist/client/checkedDirectRuntime.d.ts +11 -1
  5. package/dist/client/checkedDirectRuntime.js +19 -2
  6. package/dist/client/directClientRuntime.d.ts +18 -1
  7. package/dist/client/directClientRuntime.js +15 -3
  8. package/dist/client/directClientVersion.d.ts +2 -0
  9. package/dist/client/directClientVersion.js +2 -0
  10. package/dist/client/generateClient.js +72 -16
  11. package/dist/client/generateDirectClient.js +14 -9
  12. package/dist/client/generateOperations.js +30 -11
  13. package/dist/client/generateUtils.js +5 -1
  14. package/dist/compiler/canonicalGraph.d.ts +4 -15
  15. package/dist/compiler/canonicalGraph.js +1 -8
  16. package/dist/compiler/componentRecordProjection.d.ts +3 -0
  17. package/dist/compiler/componentRecordProjection.js +10 -0
  18. package/dist/compiler/declarationIdentity.d.ts +22 -0
  19. package/dist/compiler/declarationIdentity.js +9 -0
  20. package/dist/compiler/directCodec.d.ts +22 -2
  21. package/dist/compiler/directCodec.js +40 -7
  22. package/dist/compiler/directOperation.d.ts +28 -5
  23. package/dist/compiler/directOperation.js +84 -14
  24. package/dist/compiler/directSoap.d.ts +40 -10
  25. package/dist/compiler/directSoap.js +151 -18
  26. package/dist/compiler/directSoapSource.js +3 -2
  27. package/dist/compiler/directSourceCapsule.js +69 -4
  28. package/dist/compiler/directStructure.js +6 -2
  29. package/dist/compiler/directStructurePlan.d.ts +10 -1
  30. package/dist/compiler/directStructurePlan.js +27 -7
  31. package/dist/compiler/directValues.d.ts +15 -3
  32. package/dist/compiler/directValues.js +20 -4
  33. package/dist/compiler/legacyDeclarations.d.ts +26 -0
  34. package/dist/compiler/legacyDeclarations.js +144 -0
  35. package/dist/compiler/projectionScalar.d.ts +18 -1
  36. package/dist/compiler/projectionScalar.js +47 -13
  37. package/dist/compiler/rpcStringValues.d.ts +30 -0
  38. package/dist/compiler/rpcStringValues.js +196 -0
  39. package/dist/compiler/rpcTypedValues.d.ts +48 -0
  40. package/dist/compiler/rpcTypedValues.js +190 -0
  41. package/dist/compiler/schemaCompiler.js +44 -109
  42. package/dist/compiler/semanticCatalog.d.ts +2 -2
  43. package/dist/compiler/soapHeaders.d.ts +10 -4
  44. package/dist/compiler/soapHeaders.js +28 -9
  45. package/dist/gateway/generateCheckedGateway.js +26 -6
  46. package/dist/gateway/generateComposedGateway.d.ts +16 -0
  47. package/dist/gateway/generateComposedGateway.js +65 -0
  48. package/dist/gateway/generateGateway.js +1 -0
  49. package/dist/gateway/generators.js +19 -4
  50. package/dist/gateway/helpers.d.ts +1 -0
  51. package/dist/gateway/helpers.js +15 -0
  52. package/dist/generation/componentShape.js +25 -1
  53. package/dist/index.d.ts +5 -1
  54. package/dist/index.js +3 -1
  55. package/dist/loader/orderedSyntax.d.ts +4 -0
  56. package/dist/loader/orderedSyntax.js +18 -4
  57. package/dist/multiServicePipeline.d.ts +41 -0
  58. package/dist/multiServicePipeline.js +287 -0
  59. package/dist/openapi/composeOpenAPI.d.ts +29 -0
  60. package/dist/openapi/composeOpenAPI.js +322 -0
  61. package/dist/pipeline.d.ts +1 -1
  62. package/dist/pipeline.js +2 -0
  63. package/docs/agent-skill.md +10 -1
  64. package/docs/api-reference.md +127 -9
  65. package/docs/checked-gateway.md +10 -0
  66. package/docs/checked-generation.md +11 -5
  67. package/docs/cli-reference.md +25 -5
  68. package/docs/concepts.md +4 -5
  69. package/docs/configuration.md +10 -3
  70. package/docs/corpus.md +1 -1
  71. package/docs/gateway-guide.md +104 -27
  72. package/docs/generated-code.md +12 -6
  73. package/docs/migration-playbook.md +4 -0
  74. package/docs/migration.md +134 -6
  75. package/docs/output-anatomy.md +20 -17
  76. package/docs/production.md +7 -5
  77. package/docs/start-here.md +12 -2
  78. package/docs/supported-patterns.md +23 -0
  79. package/docs/testing.md +2 -0
  80. package/docs/troubleshooting.md +3 -1
  81. package/llms.txt +9 -1
  82. package/package.json +2 -2
  83. package/src/runtime/clientStreamMethods.tpl.txt +156 -148
  84. package/src/runtime/operationsStreamHelper.tpl.txt +6 -6
  85. package/src/runtime/streamXml.ts +48 -20
@@ -316,6 +316,10 @@ export function checkDirectSourceCompatibility(expected, contract, selection, si
316
316
  const componentVersions = Object.freeze({ ...versions, scope: 'component-soap11-utf8-graph-v1', mapping: 'component-values-v1',
317
317
  runtimePolicy: 'explicit-http-verified-https-transport-v1' });
318
318
  const scopedComponentVersions = Object.freeze({ ...componentVersions, scope: 'component-soap11-utf8-graph-v2', mapping: 'component-values-and-record-scope-v1' });
319
+ const soap12ComponentVersions = Object.freeze({ ...componentVersions, scope: 'component-soap12-document-literal-v1' });
320
+ const scopedSoap12ComponentVersions = Object.freeze({ ...scopedComponentVersions, scope: 'component-soap12-document-literal-record-v1' });
321
+ const rpcComponentVersions = Object.freeze({ ...componentVersions, scope: 'component-soap11-rpc-strings-v1', mapping: 'component-rpc-string-values-v1' });
322
+ const typedRpcComponentVersions = Object.freeze({ ...componentVersions, scope: 'component-soap11-rpc-typed-latin1-v1', mapping: 'component-rpc-typed-values-v1' });
319
323
  const componentReconstructions = new WeakMap();
320
324
  function componentFailure(error, budget) {
321
325
  return Object.freeze({ ...failure(error, budget), repair: 'Regenerate matched component artifacts from explicitly authorized original WSDL and dependencies.' });
@@ -362,15 +366,29 @@ async function componentDescriptor(contract, selection, signal, responseProjecti
362
366
  if (mapping.kind !== 'component-mapping' && mapping.kind !== 'component-record-projection')
363
367
  throw new Stop(mapping.kind === 'resource-limit' || mapping.kind === 'cancelled' ? mapping.kind : 'unsupported', mapping.rule);
364
368
  mappings.push(mapping);
369
+ if ('parts' in mapping.root)
370
+ return { kind: 'rpc-typed-parts-v1', message: mapping.root.message,
371
+ wrapper: mapping.root.wrapper, bodyNamespace: mapping.root.bodyNamespace, encoding: contract.binding.encoding,
372
+ parts: mapping.root.parts.map(part => {
373
+ const resolved = inspectDirectOperation(contract).context.resolve(part.type);
374
+ const type = resolved.kind === 'builtin' ? resolved.name : resolved.kind === 'found' && resolved.node.identity.kind === 'global'
375
+ ? resolved.node.identity.name : undefined;
376
+ if (!type)
377
+ throw new Stop('unsupported', 'rpc-named-type-required');
378
+ return { name: part.name, type };
379
+ }) };
365
380
  return { element: mapping.root.element.name, message: mapping.root.message, part: mapping.root.part };
366
381
  };
367
382
  const input = make({ kind: 'input' }), output = make({ kind: 'output' });
368
383
  const faults = contract.faults.map(fault => ({ name: fault.name, root: make({ kind: 'fault', name: fault.name }) }));
369
384
  const compatibility = { selector: contract.selector, service: owned.service, port: owned.port,
385
+ ...(contract.binding.version === '1.2' ? { binding: { version: '1.2', actionRequired: contract.binding.actionRequired } } : {}),
370
386
  action: contract.binding.action, input, output, faults };
371
387
  let projection = null;
372
388
  if (responseProjection) {
373
389
  const { companion } = inspectComponentRecordProjection(responseProjection, contract);
390
+ if ('parts' in companion.output)
391
+ throw new Stop('unsupported', 'record-projection-requires-document-output');
374
392
  const { context } = inspectDirectOperation(companion);
375
393
  projection = { spec: responseProjection.spec, source: { selector: companion.selector, action: companion.binding.action,
376
394
  output: { element: companion.output.element.name, message: companion.output.message, part: companion.output.part },
@@ -412,7 +430,11 @@ export async function createComponentSourceCapsule(contract, selection, signal,
412
430
  function componentCapsule(derived, budget) {
413
431
  const { compatibility, resources, libraries, projection } = derived;
414
432
  const extended = libraries.length > 0 || projection !== null;
415
- const value = { versions: extended ? scopedComponentVersions : componentVersions, resources, compatibility,
433
+ const rpc = 'kind' in compatibility.input && compatibility.input.kind === 'rpc-typed-parts-v1';
434
+ const typedRpc = rpc && compatibility.input.parts.some(part => part.type.namespace !== 'http://www.w3.org/2001/XMLSchema' || part.type.local !== 'string');
435
+ if (rpc && (extended || derived.applicationGroups))
436
+ throw new Stop('unsupported', 'rpc-artifact-extension');
437
+ const value = { versions: compatibility.binding?.version === '1.2' ? extended ? scopedSoap12ComponentVersions : soap12ComponentVersions : typedRpc ? typedRpcComponentVersions : rpc ? rpcComponentVersions : extended ? scopedComponentVersions : componentVersions, resources, compatibility,
416
438
  ...(extended ? { libraries, projection } : {}), ...(derived.applicationGroups ? { applicationGroups: derived.applicationGroups, applicationGroupIdentity: derived.applicationGroupIdentity } : {}) };
417
439
  return { ...value, fingerprint: hash(json(value, budget)) };
418
440
  }
@@ -470,13 +492,46 @@ function readComponent(bytes, budget, signal) {
470
492
  if (!/^[a-f0-9]{64}$/.test(parsed.applicationGroupIdentity))
471
493
  reject('application-group-identity');
472
494
  }
473
- const expectedVersions = extended ? scopedComponentVersions : componentVersions;
495
+ const typedRpc = !!parsed.versions && typeof parsed.versions === 'object' && parsed.versions.scope === typedRpcComponentVersions.scope;
496
+ const rpc = typedRpc || !!parsed.versions && typeof parsed.versions === 'object' && parsed.versions.scope === rpcComponentVersions.scope;
497
+ if (rpc && (extended || grouped))
498
+ reject('rpc-artifact-extension');
499
+ const soap12 = !!parsed.versions && typeof parsed.versions === 'object' && ['component-soap12-document-literal-v1', 'component-soap12-document-literal-record-v1'].includes(parsed.versions.scope);
500
+ const expectedVersions = soap12 ? extended ? scopedSoap12ComponentVersions : soap12ComponentVersions : typedRpc ? typedRpcComponentVersions : rpc ? rpcComponentVersions : extended ? scopedComponentVersions : componentVersions;
474
501
  const actual = record(parsed.versions, Object.keys(expectedVersions));
475
502
  for (const key of Object.keys(expectedVersions))
476
503
  if (actual[key] !== expectedVersions[key])
477
504
  reject('unsupported-version-mode-or-policy');
478
505
  validateComponentResources(parsed.resources, budget, signal);
479
- const root = (value) => { const r = record(value, ['element', 'message', 'part']); name(r.element); name(r.message); ncname(r.part); };
506
+ const root = (value) => {
507
+ if (rpc) {
508
+ const r = record(value, ['kind', 'message', 'wrapper', 'bodyNamespace', 'encoding', 'parts']);
509
+ if (r.kind !== 'rpc-typed-parts-v1' || r.encoding !== 'http://schemas.xmlsoap.org/soap/encoding/')
510
+ reject('rpc-root-profile');
511
+ name(r.message);
512
+ name(r.wrapper);
513
+ text(r.bodyNamespace);
514
+ if (!Array.isArray(r.parts) || !r.parts.length)
515
+ return reject('rpc-parts-required');
516
+ const names = new Set();
517
+ for (const part of r.parts) {
518
+ check(budget, signal);
519
+ const p = record(part, ['name', 'type']);
520
+ ncname(p.name);
521
+ name(p.type);
522
+ if (names.has(p.name))
523
+ reject('duplicate-rpc-part');
524
+ names.add(p.name);
525
+ if (!typedRpc && (p.type.namespace !== 'http://www.w3.org/2001/XMLSchema' || p.type.local !== 'string'))
526
+ reject('rpc-part-type');
527
+ }
528
+ return;
529
+ }
530
+ const r = record(value, ['element', 'message', 'part']);
531
+ name(r.element);
532
+ name(r.message);
533
+ ncname(r.part);
534
+ };
480
535
  const selector = (value) => { const s = record(value, ['portType', 'binding', 'operation']); name(s.portType); name(s.binding); ncname(s.operation); };
481
536
  if (extended) {
482
537
  validateComponentLibraries(parsed.libraries);
@@ -513,13 +568,23 @@ function readComponent(bytes, budget, signal) {
513
568
  if (!parsed.libraries.length && parsed.projection === null)
514
569
  reject('empty-component-extension');
515
570
  }
516
- const c = record(parsed.compatibility, ['selector', 'service', 'port', 'action', 'input', 'output', 'faults']);
571
+ const c = record(parsed.compatibility, ['selector', 'service', 'port', 'action', 'input', 'output', 'faults', ...(soap12 ? ['binding'] : [])]);
572
+ if (soap12) {
573
+ const binding = record(c.binding, ['version', 'actionRequired']);
574
+ if (binding.version !== '1.2' || typeof binding.actionRequired !== 'boolean')
575
+ reject('soap12-binding');
576
+ }
517
577
  selector(c.selector);
518
578
  name(c.service);
519
579
  ncname(c.port);
520
580
  text(c.action);
521
581
  root(c.input);
522
582
  root(c.output);
583
+ if (rpc) {
584
+ const parts = c.input.parts;
585
+ if (typedRpc !== parts.some(part => part.type.namespace !== 'http://www.w3.org/2001/XMLSchema' || part.type.local !== 'string'))
586
+ reject('rpc-type-version');
587
+ }
523
588
  if (!Array.isArray(c.faults))
524
589
  return reject('faults-required');
525
590
  const names = new Set();
@@ -514,8 +514,12 @@ export function matchDirectOperation(contract, direction, payload, options = {})
514
514
  throw new Stop('unsupported', 'unknown-fault');
515
515
  root = selected.root;
516
516
  }
517
- else
518
- root = contract[ownedDirection.kind];
517
+ else {
518
+ const selected = contract[ownedDirection.kind];
519
+ if ('parts' in selected)
520
+ throw new Stop('unsupported', 'direct-document-root-required');
521
+ root = selected;
522
+ }
519
523
  const matched = matchDirectProjection(context, root.element, payload, { ...options, flatOnly: true });
520
524
  if (matched.kind !== 'projection-match')
521
525
  return matched;
@@ -1,7 +1,7 @@
1
1
  /** Single native direct slot interpretation shared by matching and value mapping. */
2
2
  import type { DirectMessageRoot } from './directOperation.js';
3
3
  import type { SemanticContext } from './semanticContext.js';
4
- import type { AttributeNode, ComplexTypeNode, ElementNode, NodeId, ParticleNode } from './canonicalGraph.js';
4
+ import type { AttributeNode, ComplexTypeNode, ElementNode, GraphNode, NodeId, ParticleNode, Reference } from './canonicalGraph.js';
5
5
  import type { ExpandedName } from '../loader/orderedSyntax.js';
6
6
  import type { ProjectionScalarList } from './projectionScalar.js';
7
7
  import type { SemanticParticle, SemanticParticleView } from './particleSemanticView.js';
@@ -143,6 +143,15 @@ export declare function selectProjectionAttribute(context: SemanticContext, reco
143
143
  * The checked-direct preview adapter below retains its flat-only grammar.
144
144
  */
145
145
  export declare function planDirectProjection(context: SemanticContext, root: ElementNode, check: () => void, unsupported: (detail?: DirectProjectionUnavailable) => never): DirectProjectionPlan;
146
+ /** Plan a source-owned type using native scalar, content and particle owners.
147
+ * @param context Native source context.
148
+ * @param owner Exact source graph node owning the type reference.
149
+ * @param reference Selected source type.
150
+ * @param check Cooperative checkpoint.
151
+ * @param unsupported Explicit refusal callback.
152
+ * @returns The same native projection used by document elements, without element facts.
153
+ */
154
+ export declare function planProjectionType(context: SemanticContext, owner: GraphNode, reference: Reference, check: () => void, unsupported: (detail?: DirectProjectionUnavailable) => never): DirectProjectionPlan;
146
155
  /** Adapt the native projection to the supported flat preview without widening admission. */
147
156
  export declare function planDirectRoot(context: SemanticContext, root: DirectMessageRoot, check: () => void, unsupported: () => never): DirectRootPlan;
148
157
  /** Flat-only projection adapter; its input is derived data, never native admission. */
@@ -3,7 +3,7 @@ import { assessSourceAttributeUses } from './schemaAttributeUses.js';
3
3
  import { deriveActualComplexContent, particleContentNode } from './complexTypeContent.js';
4
4
  import { XSD_NAMESPACE, XML_NAMESPACE, isXmlNCName } from '../loader/orderedSyntax.js';
5
5
  import { occurrenceAlgebra } from './occurrenceAnalysis.js';
6
- import { describeProjectionScalar, assessProjectionScalarOperand } from './projectionScalar.js';
6
+ import { describeProjectionScalar, describeProjectionType, assessProjectionScalarOperand } from './projectionScalar.js';
7
7
  import { builtinListItem } from './datatypeValues.js';
8
8
  import { prepareSemanticParticleView, assertSemanticParticleView } from './particleSemanticView.js';
9
9
  import { effectiveSubstitutionMembers } from './schemaTypeRelations.js';
@@ -244,6 +244,20 @@ export function selectProjectionAttribute(context, record, name, check, unsuppor
244
244
  * The checked-direct preview adapter below retains its flat-only grammar.
245
245
  */
246
246
  export function planDirectProjection(context, root, check, unsupported) {
247
+ return planProjection(context, root, root.type, check, unsupported, root);
248
+ }
249
+ /** Plan a source-owned type using native scalar, content and particle owners.
250
+ * @param context Native source context.
251
+ * @param owner Exact source graph node owning the type reference.
252
+ * @param reference Selected source type.
253
+ * @param check Cooperative checkpoint.
254
+ * @param unsupported Explicit refusal callback.
255
+ * @returns The same native projection used by document elements, without element facts.
256
+ */
257
+ export function planProjectionType(context, owner, reference, check, unsupported) {
258
+ return planProjection(context, owner, reference, check, unsupported);
259
+ }
260
+ function planProjection(context, owner, reference, check, unsupported, root) {
247
261
  assertSemanticContext(context);
248
262
  if (context.kind !== 'actual')
249
263
  return unsupported();
@@ -259,13 +273,14 @@ export function planDirectProjection(context, root, check, unsupported) {
259
273
  return unsupported();
260
274
  return result.node;
261
275
  };
276
+ if (lookup(owner.id) !== owner)
277
+ return unsupported();
262
278
  const records = new Map();
263
279
  const pending = [];
264
280
  const value = (element) => {
265
281
  if (lookup(element.id) !== element)
266
282
  return unsupported();
267
283
  check();
268
- const type = context.resolve(element.type);
269
284
  if (element.abstract || element.substitutionGroup)
270
285
  return unsupported();
271
286
  const facts = { ...(element.nillable ? { nillable: true } : {}), ...(() => {
@@ -276,13 +291,18 @@ export function planDirectProjection(context, root, check, unsupported) {
276
291
  return unavailable(element, 'element-value-constraint');
277
292
  return { constraint: Object.freeze({ kind: element.value.kind, lexical: element.value.lexical.value, canonical: assessed.operand.canonical }) };
278
293
  })() };
294
+ return typeValue(element, element.type, facts);
295
+ };
296
+ const typeValue = (element, reference, facts = {}) => {
297
+ check();
298
+ const type = context.resolve(reference);
279
299
  if (type.kind === 'builtin' && !builtinListItem(type.name.local)) {
280
300
  if (!projectionScalarRepresentation(type.name))
281
301
  return unavailable(element, 'builtin-scalar-context-or-representation');
282
302
  return Object.freeze({ kind: 'scalar', builtin: type.name, ...facts });
283
303
  }
284
304
  if (type.kind === 'builtin' || type.kind === 'found' && type.node.kind === 'simpleType') {
285
- const scalar = describeProjectionScalar(context, element, check);
305
+ const scalar = describeProjectionType(context, element, reference, check);
286
306
  check();
287
307
  if (scalar.kind !== 'projection-scalar-type')
288
308
  return unavailable(element, 'rule' in scalar ? scalar.rule : 'scalar-source-definition');
@@ -295,13 +315,13 @@ export function planDirectProjection(context, root, check, unsupported) {
295
315
  return unavailable(element, 'unavailable-complex-type');
296
316
  if (!records.has(type.node.id)) {
297
317
  budget.chargeWork(64);
298
- records.set(type.node.id, { type: type.node, declaration: element, slots: [], attributes: [], content: 'element-only' });
318
+ records.set(type.node.id, { type: type.node, declaration: element, reference, slots: [], attributes: [], content: 'element-only' });
299
319
  pending.push(type.node);
300
320
  }
301
321
  return Object.freeze({ kind: 'record', type: type.node.id, ...facts });
302
322
  };
303
323
  budget.chargeWork(128);
304
- const rootValue = value(root);
324
+ const rootValue = root ? value(root) : typeValue(owner, reference);
305
325
  while (pending.length) {
306
326
  check();
307
327
  const type = pending.pop();
@@ -359,7 +379,7 @@ export function planDirectProjection(context, root, check, unsupported) {
359
379
  if (content.kind !== 'checked')
360
380
  return unavailable(type, 'native-content-properties');
361
381
  if (content.view.content.kind === 'simple') {
362
- const scalar = describeProjectionScalar(context, record.declaration, check);
382
+ const scalar = describeProjectionType(context, record.declaration, record.reference, check);
363
383
  check();
364
384
  if (scalar.kind !== 'projection-scalar-type')
365
385
  return unavailable(type, 'rule' in scalar ? scalar.rule : 'scalar-source-definition');
@@ -575,7 +595,7 @@ export function planDirectProjection(context, root, check, unsupported) {
575
595
  }
576
596
  }
577
597
  budget.chargeWork(32 + ordered.length * 64);
578
- return Object.freeze({ root: rootValue, records: Object.freeze(ordered.map(({ declaration: _declaration, grammar, ...record }) => {
598
+ return Object.freeze({ root: rootValue, records: Object.freeze(ordered.map(({ declaration: _declaration, reference: _reference, grammar, ...record }) => {
579
599
  const attributes = Object.freeze(record.attributes.map(attribute => {
580
600
  const local = attribute.declaration.name.local;
581
601
  const collision = record.slots.some(slot => slot.element.name.local === local)
@@ -1,4 +1,4 @@
1
- import type { DirectOperationContract, DirectMessageRoot } from './directOperation.js';
1
+ import type { DirectOperationContract, DirectMessageRoot, RpcMessageRoot } from './directOperation.js';
2
2
  import type { DirectDirection, DirectScalarDuty, DirectStructuralMatch } from './directStructure.js';
3
3
  import type { DirectRootPlan, DirectProjectionPlan } from './directStructurePlan.js';
4
4
  import type { SemanticContext } from './semanticContext.js';
@@ -7,6 +7,7 @@ import type { ProjectionStructuralMatch } from './directStructure.js';
7
7
  import type { ResolverUsage } from './semanticBudget.js';
8
8
  import type { SyntaxElement } from '../loader/orderedSyntax.js';
9
9
  import type { ApplicationGroupsOptions, ApplicationGroupPlan } from './applicationGroups.js';
10
+ import type { RpcPartPlan } from './rpcTypedValues.js';
10
11
  export type DirectPrimitive = string | boolean | number;
11
12
  /** Inverse construction caps; XML encoding may impose smaller byte/text/node limits. */
12
13
  export declare const DIRECT_VALUE_LIMITS: Readonly<{
@@ -28,7 +29,7 @@ export interface DirectValueMapping extends DirectRootPlan {
28
29
  readonly contextId: string;
29
30
  readonly usage: ResolverUsage;
30
31
  }
31
- export interface ComponentValueMapping {
32
+ export interface DocumentComponentValueMapping {
32
33
  readonly kind: 'component-mapping';
33
34
  readonly version: 'component-values-v1';
34
35
  readonly admitted: false;
@@ -37,6 +38,16 @@ export interface ComponentValueMapping {
37
38
  readonly contextId: string;
38
39
  readonly usage: ResolverUsage;
39
40
  }
41
+ export interface RpcComponentValueMapping {
42
+ readonly kind: 'component-mapping';
43
+ readonly version: 'component-rpc-string-values-v1' | 'component-rpc-typed-values-v1';
44
+ readonly admitted: false;
45
+ readonly root: RpcMessageRoot;
46
+ readonly direction: DirectDirection;
47
+ readonly contextId: string;
48
+ readonly usage: ResolverUsage;
49
+ }
50
+ export type ComponentValueMapping = DocumentComponentValueMapping | RpcComponentValueMapping;
40
51
  export interface DirectAssessedScalar extends DirectScalarDuty {
41
52
  readonly normalized: string;
42
53
  readonly canonical: string;
@@ -115,8 +126,9 @@ export declare function createComponentDirectionalMapping(contract: DirectOperat
115
126
  /** Authenticate the exact structured mapping and expose its existing native plan to local consumers only. */
116
127
  export declare function inspectComponentValueMapping(value: unknown, contract: DirectOperationContract): Readonly<{
117
128
  mapping: ComponentValueMapping;
118
- projection: DirectProjectionPlan;
129
+ projection?: DirectProjectionPlan;
119
130
  applicationGroups?: ApplicationGroupPlan;
131
+ rpcParts?: readonly RpcPartPlan[];
120
132
  }>;
121
133
  /** Validate scalar operands and retain nested application records without claiming source or operation admission. */
122
134
  export declare function assessProjectionScalars(context: SemanticContext, supplied: unknown, options?: Options, mapping?: ComponentValueMapping): ProjectionValueReceipt | DirectValueFailure;
@@ -3,7 +3,7 @@ import { types } from 'node:util';
3
3
  /** Internal direct value chain. No XML encoding, transport or runtime admission. */
4
4
  import { checkSemanticBudget } from './semanticBudget.js';
5
5
  import { DataOwnershipLimitError } from './dataOwnership.js';
6
- import { inspectDirectOperation } from './directOperation.js';
6
+ import { inspectDirectOperation, isRpcMessageRoot } from './directOperation.js';
7
7
  import { inspectDirectStructuralMatch, matchDirectOperation } from './directStructure.js';
8
8
  import { planDirectProjection, flatDirectProjection, projectionScalarRepresentation, resolveProjectionWildcard, selectProjectionWildcard, selectProjectionAttribute, isXmlCharacters, isXmlNamespaceBinding } from './directStructurePlan.js';
9
9
  import { assertSemanticContext } from './semanticContext.js';
@@ -12,6 +12,7 @@ import { datatypeValues, normalizeWhitespace, whitespaceFor } from './datatypeVa
12
12
  import { assessProjectionScalarOperand } from './projectionScalar.js';
13
13
  import { isXmlNCName, XML_NAMESPACE, XSD_NAMESPACE } from '../loader/orderedSyntax.js';
14
14
  import { planApplicationGroups, mapApplicationGroups, parseApplicationGroups, ApplicationGroupValueError } from './applicationGroups.js';
15
+ import { planRpcParts } from './rpcTypedValues.js';
15
16
  /** Inverse construction caps; XML encoding may impose smaller byte/text/node limits. */
16
17
  export const DIRECT_VALUE_LIMITS = Object.freeze({ maxText: 1024 * 1024, maxItems: 100_000 });
17
18
  export const DIRECT_VALUE_VERSION = 'direct-values-v1';
@@ -125,6 +126,8 @@ function mappingFor(contract, direction, s) {
125
126
  if (contract.basis !== 'native-direct-premises-v1' || contract.correspondence !== 'dated-XSD-2004-direct-v1')
126
127
  throw new Stop('unsupported', 'direct-mapping-version');
127
128
  const selected = mappingRoot(contract, direction, s), { root } = selected;
129
+ if (isRpcMessageRoot(root))
130
+ throw new Stop('unsupported', 'direct-mapping-version');
128
131
  const unsupported = () => { throw new Stop('unsupported', 'native-direct-shape', root.element.context.source.path); };
129
132
  const projection = planDirectProjection(context, root.element, check, unsupported);
130
133
  const plan = flatDirectProjection(projection, check, unsupported);
@@ -149,7 +152,18 @@ export function createComponentValueMapping(contract, direction, options = {}, a
149
152
  if (contract.basis !== 'native-component-premises-v1' || contract.correspondence !== 'dated-XSD-2004-components-v1')
150
153
  throw new Stop('unsupported', 'component-mapping-version');
151
154
  const selected = mappingRoot(contract, direction, s);
152
- const projection = planDirectProjection(context, selected.root.element, s.check, () => { throw new Stop('unsupported', 'native-component-shape', selected.root.element.context.source.path); });
155
+ if (isRpcMessageRoot(selected.root)) {
156
+ if (applicationGroups !== undefined)
157
+ throw new Stop('unsupported', 'rpc-application-groups');
158
+ const typed = isRpcMessageRoot(contract.input) && contract.input.parts.some(part => part.type.kind !== 'builtin' || part.type.name.local !== 'string' || part.type.name.namespace !== XSD_NAMESPACE);
159
+ const rpcParts = typed ? planRpcParts(context, selected.root, { ...s, fail: (kind, rule) => { throw new Stop(kind === 'mismatch' ? 'value-invalid' : kind, rule); } }) : undefined;
160
+ const mapping = s.publish({ kind: 'component-mapping', version: typed ? 'component-rpc-typed-values-v1' : 'component-rpc-string-values-v1', admitted: false,
161
+ root: selected.root, direction: selected.direction, contextId: context.contextId });
162
+ componentMappings.set(mapping, Object.freeze({ mapping, contract, rpcParts }));
163
+ return mapping;
164
+ }
165
+ const element = selected.root.element;
166
+ const projection = planDirectProjection(context, element, s.check, () => { throw new Stop('unsupported', 'native-component-shape', element.context.source.path); });
153
167
  const mapping = s.publish({ kind: 'component-mapping', version: 'component-values-v1',
154
168
  admitted: false, root: selected.root, direction: selected.direction, contextId: context.contextId });
155
169
  const groupOptions = applicationGroups ? directDataOwnership(s.budget).freeze(parseApplicationGroups(applicationGroups)) : undefined;
@@ -174,7 +188,7 @@ export function inspectComponentValueMapping(value, contract) {
174
188
  const owned = componentMappings.get(value);
175
189
  if (!owned || owned.contract !== contract)
176
190
  throw new TypeError('Fresh matching component value mapping required');
177
- return Object.freeze({ mapping: owned.mapping, projection: owned.projection, ...(owned.applicationGroups ? { applicationGroups: owned.applicationGroups } : {}) });
191
+ return Object.freeze({ mapping: owned.mapping, projection: owned.projection, rpcParts: owned.rpcParts, ...(owned.applicationGroups ? { applicationGroups: owned.applicationGroups } : {}) });
178
192
  }
179
193
  function scalar(duty, s, context) {
180
194
  const { budget, check } = s;
@@ -448,7 +462,7 @@ export function assessProjectionScalars(context, supplied, options = {}, mapping
448
462
  }
449
463
  let value = projectValue(structural.tree, operands, s);
450
464
  const owned = mapping && componentMappings.get(mapping);
451
- if (owned?.applicationGroups)
465
+ if (owned?.applicationGroups && owned.projection)
452
466
  value = mapApplicationGroups(owned.applicationGroups, owned.projection, value, 'from-native', s.check);
453
467
  const receipt = s.publish({ kind: 'projection-value', scope: 'direct-structure-and-scalars', admitted: false,
454
468
  root: structural.root, contextId: context.contextId, structural, operands, value });
@@ -1074,6 +1088,8 @@ export function expandProjectionValue(context, root, application, options = {},
1074
1088
  throw new ApplicationGroupValueError('application-group-data-required');
1075
1089
  throw error;
1076
1090
  }
1091
+ if (!owned.projection)
1092
+ throw new TypeError('Native document projection required');
1077
1093
  application = mapApplicationGroups(owned.applicationGroups, owned.projection, copied, 'to-native', s.check);
1078
1094
  }
1079
1095
  const payload = buildProjectionPayload(context, root, plan, application, options, s);
@@ -0,0 +1,26 @@
1
+ import { type NodeId } from "./declarationIdentity.js";
2
+ export type LegacyGlobal = Readonly<{
3
+ kind: "complex" | "simple" | "element";
4
+ name: string;
5
+ ns: string;
6
+ node: unknown;
7
+ prefixes: Record<string, string>;
8
+ }>;
9
+ /** Index legacy declarations without importing the checked loader's source or acceptance policies.
10
+ * @constraints Paths count equal role/name peers within a parent, never text nodes or unrelated global declarations.
11
+ * @constraints Name allocation is local to this compilation; independent catalogs still require conservative conflict checks.
12
+ */
13
+ export declare class LegacyDeclarations {
14
+ private readonly declarations;
15
+ private readonly names;
16
+ private readonly surfaces;
17
+ private readonly inlineByOwner;
18
+ constructor(globals: readonly LegacyGlobal[]);
19
+ type(ns: string, name: string): NodeId;
20
+ element(ns: string, name: string): NodeId;
21
+ surface(ns: string, name: string): NodeId;
22
+ name(id: NodeId): string;
23
+ inline(owner: NodeId, element: unknown): NodeId;
24
+ private walk;
25
+ private allocate;
26
+ }
@@ -0,0 +1,144 @@
1
+ import { createHash } from "node:crypto";
2
+ import { globalId, scopedId } from "./declarationIdentity.js";
3
+ import { pascal, resolveQName } from "../util/tools.js";
4
+ const object = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
5
+ const local = (key) => key.slice(key.indexOf(":") + 1);
6
+ const attribute = (node, name) => object(node) && typeof node[`@_${name}`] === "string" ? node[`@_${name}`] : "";
7
+ const children = (node, role) => object(node) ? Object.entries(node)
8
+ .filter(([key]) => local(key) === role).flatMap(([, value]) => Array.isArray(value) ? value : [value]) : [];
9
+ /** Index legacy declarations without importing the checked loader's source or acceptance policies.
10
+ * @constraints Paths count equal role/name peers within a parent, never text nodes or unrelated global declarations.
11
+ * @constraints Name allocation is local to this compilation; independent catalogs still require conservative conflict checks.
12
+ */
13
+ export class LegacyDeclarations {
14
+ declarations = new Map();
15
+ names = new Map();
16
+ surfaces = new Map();
17
+ inlineByOwner = new Map();
18
+ constructor(globals) {
19
+ const named = new Set(globals.filter(g => g.kind !== "element").map(g => this.type(g.ns, g.name)));
20
+ for (const g of globals) {
21
+ const id = g.kind === "element" ? this.element(g.ns, g.name) : this.type(g.ns, g.name);
22
+ if (g.kind === "element") {
23
+ const target = attribute(g.node, "type");
24
+ const q = target ? resolveQName(target, g.ns, g.prefixes) : undefined;
25
+ if (q && q.ns === g.ns && q.local === g.name && named.has(this.type(q.ns, q.local))) {
26
+ this.surfaces.set(id, this.type(q.ns, q.local));
27
+ continue;
28
+ }
29
+ }
30
+ const body = g.kind === "element" ? children(g.node, "complexType")[0] : g.node;
31
+ const surface = g.kind === "element" && body ? scopedId(id, "complexType", "type") : id;
32
+ this.surfaces.set(id, surface);
33
+ this.declarations.set(surface, { id: surface, candidate: pascal(g.name), stem: pascal(g.name), anonymous: false });
34
+ if (body && g.kind !== "simple")
35
+ this.walk(surface, body, pascal(g.name), []);
36
+ }
37
+ this.allocate();
38
+ }
39
+ type(ns, name) { return globalId("type", { namespace: ns, local: name }); }
40
+ element(ns, name) { return globalId("element", { namespace: ns, local: name }); }
41
+ surface(ns, name) {
42
+ const id = this.element(ns, name);
43
+ return this.surfaces.get(id) ?? id;
44
+ }
45
+ name(id) {
46
+ const name = this.names.get(id);
47
+ if (!name)
48
+ throw new Error(`Missing legacy declaration name: ${id}`);
49
+ return name;
50
+ }
51
+ inline(owner, element) {
52
+ const id = object(element) ? this.inlineByOwner.get(owner)?.get(element) : undefined;
53
+ if (!id)
54
+ throw new Error(`Missing inline declaration in ${owner}`);
55
+ return id;
56
+ }
57
+ walk(owner, node, stem, path) {
58
+ if (!object(node))
59
+ return;
60
+ const peers = new Map();
61
+ for (const [key, value] of Object.entries(node)) {
62
+ const role = local(key);
63
+ if (!["sequence", "choice", "all", "element", "complexContent", "simpleContent", "extension", "restriction"].includes(role))
64
+ continue;
65
+ for (const child of Array.isArray(value) ? value : [value]) {
66
+ const xmlName = attribute(child, "name") || attribute(child, "ref").split(":").at(-1) || "";
67
+ const peer = JSON.stringify([role, xmlName]);
68
+ const ordinal = peers.get(peer) ?? 0;
69
+ peers.set(peer, ordinal + 1);
70
+ const childPath = [...path, JSON.stringify([role, xmlName, ordinal])];
71
+ if (role === "element") {
72
+ const body = children(child, "complexType")[0];
73
+ if (!body || !object(child))
74
+ continue;
75
+ const elementId = scopedId(owner, JSON.stringify(childPath), "element");
76
+ const id = scopedId(elementId, "complexType", "type");
77
+ const candidate = pascal(xmlName);
78
+ const childStem = `${stem}${candidate}`;
79
+ this.declarations.set(id, { id, candidate, stem: childStem, anonymous: true });
80
+ let byNode = this.inlineByOwner.get(owner);
81
+ if (!byNode)
82
+ this.inlineByOwner.set(owner, byNode = new WeakMap());
83
+ byNode.set(child, id);
84
+ this.walk(id, body, childStem, []);
85
+ }
86
+ else
87
+ this.walk(owner, child, stem, childPath);
88
+ }
89
+ }
90
+ }
91
+ allocate() {
92
+ const groups = new Map();
93
+ for (const d of this.declarations.values()) {
94
+ const group = groups.get(d.candidate) ?? [];
95
+ group.push(d);
96
+ groups.set(d.candidate, group);
97
+ }
98
+ const proposed = new Map();
99
+ const fixed = new Set();
100
+ const preserved = new Set();
101
+ for (const [candidate, group] of groups) {
102
+ const named = group.filter(d => !d.anonymous);
103
+ if (group.length === 1 || named.length === 1) {
104
+ const declaration = group.length === 1 ? group[0] : named[0];
105
+ proposed.set(declaration.id, candidate);
106
+ preserved.add(declaration.id);
107
+ fixed.add(candidate);
108
+ }
109
+ for (const d of group) {
110
+ if (!proposed.has(d.id))
111
+ proposed.set(d.id, d.anonymous ? d.stem : d.candidate);
112
+ }
113
+ }
114
+ // @why No traversal-order winner: every unresolved member of a collision receives an identity-derived suffix.
115
+ const counts = new Map();
116
+ for (const name of proposed.values())
117
+ counts.set(name, (counts.get(name) ?? 0) + 1);
118
+ const pending = [];
119
+ for (const d of this.declarations.values()) {
120
+ const name = proposed.get(d.id);
121
+ if (preserved.has(d.id) || (counts.get(name) === 1 && !fixed.has(name)))
122
+ this.names.set(d.id, name);
123
+ else
124
+ pending.push(d);
125
+ }
126
+ const used = new Set(this.names.values());
127
+ for (let length = 12; pending.length > 0; length += 4) {
128
+ if (length > 64)
129
+ throw new Error("Cannot allocate unique legacy declaration names");
130
+ const candidates = pending.map(d => `${proposed.get(d.id)}_${createHash("sha256").update(d.id).digest("hex").slice(0, length)}`);
131
+ const occurrences = new Map();
132
+ for (const name of candidates)
133
+ occurrences.set(name, (occurrences.get(name) ?? 0) + 1);
134
+ for (let i = pending.length - 1; i >= 0; i--) {
135
+ const name = candidates[i];
136
+ if (used.has(name) || occurrences.get(name) > 1)
137
+ continue;
138
+ this.names.set(pending[i].id, name);
139
+ used.add(name);
140
+ pending.splice(i, 1);
141
+ }
142
+ }
143
+ }
144
+ }
@@ -1,5 +1,5 @@
1
1
  import type { SemanticContext } from './semanticContext.js';
2
- import type { AttributeNode, ElementNode } from './canonicalGraph.js';
2
+ import type { AttributeNode, ElementNode, GraphNode, Reference } from './canonicalGraph.js';
3
3
  import type { DatatypeOperand } from './datatypeValues.js';
4
4
  import type { ExpandedName } from '../loader/orderedSyntax.js';
5
5
  import type { ResourceLimitFailure } from './semanticBudget.js';
@@ -29,4 +29,21 @@ type OperandResult = Readonly<{
29
29
  export declare function describeProjectionScalar(context: SemanticContext, declaration: Declaration, check?: () => void): DescriptionResult;
30
30
  /** A successful calculation is payload-only data; it grants no schema, operation or portable artifact authority. */
31
31
  export declare function assessProjectionScalarOperand(context: SemanticContext, declaration: Declaration, lexical: DatatypeLexicalOperand, check?: () => void): OperandResult;
32
+ /** Describe a source-owned type without inventing an element declaration.
33
+ * @param context Native source context.
34
+ * @param owner Exact graph node owning the reference.
35
+ * @param reference Source-selected type reference.
36
+ * @param check Cooperative budget/cancellation checkpoint.
37
+ * @returns The existing native scalar description or explicit refusal.
38
+ */
39
+ export declare function describeProjectionType(context: SemanticContext, owner: GraphNode, reference: Reference, check?: () => void): DescriptionResult;
40
+ /** Assess a typed value through the same native restrictions as element values.
41
+ * @param context Native source context.
42
+ * @param owner Exact source node owning the reference.
43
+ * @param reference Source-selected type reference.
44
+ * @param lexical Observed lexical value and namespace context.
45
+ * @param check Cooperative checkpoint.
46
+ * @returns Native datatype operand or explicit refusal.
47
+ */
48
+ export declare function assessProjectionTypeOperand(context: SemanticContext, owner: GraphNode, reference: Reference, lexical: DatatypeLexicalOperand, check?: () => void): OperandResult;
32
49
  export {};