@openlup/core 0.0.0 → 0.7.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 (192) hide show
  1. package/CHANGELOG.md +225 -0
  2. package/CODE_OF_CONDUCT.md +39 -0
  3. package/CONTRIBUTING.md +34 -0
  4. package/LICENSE +204 -0
  5. package/MAINTAINERS.md +33 -0
  6. package/README.md +85 -3
  7. package/SECURITY.md +29 -0
  8. package/dist/bundle/contracts.d.ts +9 -0
  9. package/dist/bundle/contracts.js +1 -0
  10. package/dist/bundle/ports.d.ts +41 -0
  11. package/dist/bundle/ports.js +1 -0
  12. package/dist/catalog/identifiers.d.ts +31 -0
  13. package/dist/catalog/identifiers.js +46 -0
  14. package/dist/catalog/index.d.ts +2 -0
  15. package/dist/catalog/index.js +2 -0
  16. package/dist/checkout/idempotency.d.ts +29 -0
  17. package/dist/checkout/idempotency.js +37 -0
  18. package/dist/checkout/index.d.ts +2 -0
  19. package/dist/checkout/index.js +2 -0
  20. package/dist/company-identity/contracts.d.ts +220 -0
  21. package/dist/company-identity/contracts.js +167 -0
  22. package/dist/company-identity/index.d.ts +6 -0
  23. package/dist/company-identity/index.js +2 -0
  24. package/dist/company-identity/ports.d.ts +13 -0
  25. package/dist/company-identity/ports.js +1 -0
  26. package/dist/fulfillment/facts.d.ts +103 -0
  27. package/dist/fulfillment/facts.js +195 -0
  28. package/dist/fulfillment/index.d.ts +4 -0
  29. package/dist/fulfillment/index.js +2 -0
  30. package/dist/inventory/atp.d.ts +172 -0
  31. package/dist/inventory/atp.js +211 -0
  32. package/dist/inventory/index.d.ts +2 -0
  33. package/dist/inventory/index.js +2 -0
  34. package/dist/marketing/research/contracts.d.ts +75 -0
  35. package/dist/marketing/research/contracts.js +60 -0
  36. package/dist/marketing/research/index.d.ts +4 -0
  37. package/dist/marketing/research/index.js +4 -0
  38. package/dist/marketing/research/ports.d.ts +15 -0
  39. package/dist/marketing/research/ports.js +1 -0
  40. package/dist/partners/index.d.ts +4 -0
  41. package/dist/partners/index.js +4 -0
  42. package/dist/partners/ports.d.ts +12 -0
  43. package/dist/partners/ports.js +1 -0
  44. package/dist/partners/status.d.ts +48 -0
  45. package/dist/partners/status.js +35 -0
  46. package/dist/payment/executionBaseContracts.d.ts +81 -0
  47. package/dist/payment/executionBaseContracts.js +8 -0
  48. package/dist/payment/index.d.ts +36 -0
  49. package/dist/payment/index.js +18 -0
  50. package/dist/payment/methodLifecycle.d.ts +91 -0
  51. package/dist/payment/methodLifecycle.js +76 -0
  52. package/dist/payment/paymentControlTypes.d.ts +135 -0
  53. package/dist/payment/paymentControlTypes.js +110 -0
  54. package/dist/payment/paymentFailureTaxonomy.d.ts +80 -0
  55. package/dist/payment/paymentFailureTaxonomy.js +155 -0
  56. package/dist/payment/paymentFailureTaxonomyContracts.d.ts +106 -0
  57. package/dist/payment/paymentFailureTaxonomyContracts.js +177 -0
  58. package/dist/payment/paymentRecovery.d.ts +26 -0
  59. package/dist/payment/paymentRecovery.js +73 -0
  60. package/dist/payment/paymentRecoveryContracts.d.ts +53 -0
  61. package/dist/payment/paymentRecoveryContracts.js +10 -0
  62. package/dist/payment/paymentStateMachine.d.ts +28 -0
  63. package/dist/payment/paymentStateMachine.js +184 -0
  64. package/dist/payment/providerAttemptIdempotency.d.ts +23 -0
  65. package/dist/payment/providerAttemptIdempotency.js +31 -0
  66. package/dist/payment/providerCapability.d.ts +148 -0
  67. package/dist/payment/providerCapability.js +13 -0
  68. package/dist/platform-runtime/contracts.d.ts +9 -0
  69. package/dist/platform-runtime/contracts.js +13 -0
  70. package/dist/platform-runtime/index.d.ts +10 -0
  71. package/dist/platform-runtime/index.js +4 -0
  72. package/dist/platform-runtime/platformKernel.d.ts +44 -0
  73. package/dist/platform-runtime/platformKernel.js +39 -0
  74. package/dist/platform-runtime/ports.d.ts +100 -0
  75. package/dist/platform-runtime/ports.js +1 -0
  76. package/dist/pricing/index.d.ts +8 -0
  77. package/dist/pricing/index.js +8 -0
  78. package/dist/pricing/ports.d.ts +22 -0
  79. package/dist/pricing/ports.js +7 -0
  80. package/dist/pricing/pricingBreakdown.d.ts +86 -0
  81. package/dist/pricing/pricingBreakdown.js +155 -0
  82. package/dist/pricing/targetPriceAllocation.d.ts +97 -0
  83. package/dist/pricing/targetPriceAllocation.js +202 -0
  84. package/dist/pricing/types.d.ts +32 -0
  85. package/dist/pricing/types.js +4 -0
  86. package/dist/promo/adjustmentEngine.d.ts +4 -0
  87. package/dist/promo/adjustmentEngine.js +194 -0
  88. package/dist/promo/adjustmentTypes.d.ts +103 -0
  89. package/dist/promo/adjustmentTypes.js +13 -0
  90. package/dist/promo/index.d.ts +8 -0
  91. package/dist/promo/index.js +8 -0
  92. package/dist/promo/promoEvaluator.d.ts +25 -0
  93. package/dist/promo/promoEvaluator.js +135 -0
  94. package/dist/promo/types.d.ts +86 -0
  95. package/dist/promo/types.js +12 -0
  96. package/dist/risk/core/evaluator.d.ts +3 -0
  97. package/dist/risk/core/evaluator.js +32 -0
  98. package/dist/risk/core/rules.d.ts +3 -0
  99. package/dist/risk/core/rules.js +118 -0
  100. package/dist/risk/core/types.d.ts +65 -0
  101. package/dist/risk/core/types.js +1 -0
  102. package/dist/risk/index.d.ts +8 -0
  103. package/dist/risk/index.js +8 -0
  104. package/dist/risk/types.d.ts +32 -0
  105. package/dist/risk/types.js +43 -0
  106. package/dist/shipping/index.d.ts +4 -0
  107. package/dist/shipping/index.js +4 -0
  108. package/dist/shipping/shippingResolver.d.ts +26 -0
  109. package/dist/shipping/shippingResolver.js +88 -0
  110. package/dist/shipping/types.d.ts +45 -0
  111. package/dist/shipping/types.js +4 -0
  112. package/dist/subscription/cycleHardening.d.ts +95 -0
  113. package/dist/subscription/cycleHardening.js +118 -0
  114. package/dist/subscription/index.d.ts +14 -0
  115. package/dist/subscription/index.js +14 -0
  116. package/dist/subscription/subscriptionEngineCore.d.ts +13 -0
  117. package/dist/subscription/subscriptionEngineCore.js +145 -0
  118. package/dist/subscription/subscriptionEngineLifecycle.d.ts +150 -0
  119. package/dist/subscription/subscriptionEngineLifecycle.js +433 -0
  120. package/dist/subscription/subscriptionEnginePayment.d.ts +25 -0
  121. package/dist/subscription/subscriptionEnginePayment.js +127 -0
  122. package/dist/subscription/subscriptionEngineTypes.d.ts +94 -0
  123. package/dist/subscription/subscriptionEngineTypes.js +4 -0
  124. package/dist/subscription/subscriptionEngineUtils.d.ts +32 -0
  125. package/dist/subscription/subscriptionEngineUtils.js +74 -0
  126. package/dist/subscription/types.d.ts +58 -0
  127. package/dist/subscription/types.js +47 -0
  128. package/dist/testing.d.ts +48 -0
  129. package/dist/testing.js +105 -0
  130. package/package.json +215 -4
  131. package/release-gates.json +232 -0
  132. package/src/bundle/contracts.ts +15 -0
  133. package/src/bundle/ports.ts +32 -0
  134. package/src/catalog/identifiers.ts +50 -0
  135. package/src/catalog/index.ts +2 -0
  136. package/src/checkout/idempotency.ts +49 -0
  137. package/src/checkout/index.ts +2 -0
  138. package/src/company-identity/contracts.ts +208 -0
  139. package/src/company-identity/index.ts +28 -0
  140. package/src/company-identity/ports.ts +19 -0
  141. package/src/fulfillment/facts.ts +300 -0
  142. package/src/fulfillment/index.ts +34 -0
  143. package/src/inventory/atp.ts +249 -0
  144. package/src/inventory/index.ts +2 -0
  145. package/src/marketing/research/contracts.ts +91 -0
  146. package/src/marketing/research/index.ts +4 -0
  147. package/src/marketing/research/ports.ts +26 -0
  148. package/src/partners/index.ts +4 -0
  149. package/src/partners/ports.ts +18 -0
  150. package/src/partners/status.ts +49 -0
  151. package/src/payment/executionBaseContracts.ts +93 -0
  152. package/src/payment/index.ts +128 -0
  153. package/src/payment/methodLifecycle.ts +130 -0
  154. package/src/payment/paymentControlTypes.ts +197 -0
  155. package/src/payment/paymentFailureTaxonomy.ts +201 -0
  156. package/src/payment/paymentFailureTaxonomyContracts.ts +228 -0
  157. package/src/payment/paymentRecovery.ts +95 -0
  158. package/src/payment/paymentRecoveryContracts.ts +61 -0
  159. package/src/payment/paymentStateMachine.ts +263 -0
  160. package/src/payment/providerAttemptIdempotency.ts +57 -0
  161. package/src/payment/providerCapability.ts +172 -0
  162. package/src/platform-runtime/contracts.ts +33 -0
  163. package/src/platform-runtime/index.ts +36 -0
  164. package/src/platform-runtime/platformKernel.ts +86 -0
  165. package/src/platform-runtime/ports.ts +88 -0
  166. package/src/pricing/index.ts +8 -0
  167. package/src/pricing/ports.ts +27 -0
  168. package/src/pricing/pricingBreakdown.ts +243 -0
  169. package/src/pricing/targetPriceAllocation.ts +293 -0
  170. package/src/pricing/types.ts +36 -0
  171. package/src/promo/adjustmentEngine.ts +253 -0
  172. package/src/promo/adjustmentTypes.ts +94 -0
  173. package/src/promo/index.ts +8 -0
  174. package/src/promo/promoEvaluator.ts +137 -0
  175. package/src/promo/types.ts +97 -0
  176. package/src/risk/core/evaluator.ts +41 -0
  177. package/src/risk/core/rules.ts +128 -0
  178. package/src/risk/core/types.ts +73 -0
  179. package/src/risk/index.ts +8 -0
  180. package/src/risk/types.ts +60 -0
  181. package/src/shipping/index.ts +4 -0
  182. package/src/shipping/shippingResolver.ts +101 -0
  183. package/src/shipping/types.ts +49 -0
  184. package/src/subscription/cycleHardening.ts +174 -0
  185. package/src/subscription/index.ts +14 -0
  186. package/src/subscription/subscriptionEngineCore.ts +181 -0
  187. package/src/subscription/subscriptionEngineLifecycle.ts +574 -0
  188. package/src/subscription/subscriptionEnginePayment.ts +179 -0
  189. package/src/subscription/subscriptionEngineTypes.ts +114 -0
  190. package/src/subscription/subscriptionEngineUtils.ts +110 -0
  191. package/src/subscription/types.ts +104 -0
  192. package/src/testing.ts +169 -0
@@ -0,0 +1,9 @@
1
+ import type { BundleLineRef, CompositionConstraint } from "./ports.js";
2
+ /** @beta */
3
+ export type { BundleLineRef, CompositionConstraint, CompositionRulesPort, } from "./ports.js";
4
+ /** @beta */
5
+ export interface Bundle {
6
+ coreLines: BundleLineRef[];
7
+ addonLines: BundleLineRef[];
8
+ constraint: CompositionConstraint;
9
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,41 @@
1
+ /** Opaque, adopter-defined sizing anchor with a minimal discriminator. */
2
+ /** @beta */
3
+ export interface CompositionConstraint {
4
+ /** Adapter-owned constraint family, for example "fixed.catalog". */
5
+ kind: string;
6
+ /** Adapter-owned schema version for data. */
7
+ version: number;
8
+ /** Adapter-owned payload; core passes it through without inspecting it. */
9
+ data: Record<string, unknown>;
10
+ }
11
+ /** @beta */
12
+ export interface BundleLineRef {
13
+ variantId: string;
14
+ qty: number;
15
+ isAddon: boolean;
16
+ }
17
+ /** @beta */
18
+ export interface CompositionRulesPort {
19
+ validateComposition(input: {
20
+ coreLines: BundleLineRef[];
21
+ addonLines: BundleLineRef[];
22
+ constraint: CompositionConstraint;
23
+ }): Promise<{
24
+ ok: true;
25
+ } | {
26
+ ok: false;
27
+ code: string;
28
+ details?: Record<string, unknown>;
29
+ }>;
30
+ resizeComposition(input: {
31
+ coreLines: BundleLineRef[];
32
+ constraint: CompositionConstraint;
33
+ lever: {
34
+ kind: string;
35
+ value: unknown;
36
+ };
37
+ }): Promise<{
38
+ coreLines: BundleLineRef[];
39
+ constraint: CompositionConstraint;
40
+ } | null>;
41
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,31 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Open-but-validated catalog identifier primitives.
4
+ *
5
+ * These schemas validate shape only; membership belongs to the host
6
+ * application's catalog read port. A runtime-editable catalog must accept new
7
+ * slugs, SKUs, product ids, and variant ids without requiring a package release.
8
+ * Keep these primitives format-bound, not enum-bound.
9
+ */
10
+ /** @beta */
11
+ export declare const catalogSlugFormat: RegExp;
12
+ /** @beta */
13
+ export declare const slugSchema: z.ZodString;
14
+ /**
15
+ * A purchasable SKU. Charset and length are bounded, but the schema does not
16
+ * encode packaging, weight, brand, or merchant-specific prefixes.
17
+ */
18
+ /** @beta */
19
+ export declare const skuSchema: z.ZodString;
20
+ /**
21
+ * A catalog product id. Accepts static ids and database ids as long as their
22
+ * shape is bounded; existence is checked by the host catalog data source.
23
+ */
24
+ /** @beta */
25
+ export declare const catalogProductIdSchema: z.ZodString;
26
+ /**
27
+ * A variant id. Accepts static ids and database ids without requiring a literal
28
+ * prefix owned by the package.
29
+ */
30
+ /** @beta */
31
+ export declare const variantIdSchema: z.ZodString;
@@ -0,0 +1,46 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Open-but-validated catalog identifier primitives.
4
+ *
5
+ * These schemas validate shape only; membership belongs to the host
6
+ * application's catalog read port. A runtime-editable catalog must accept new
7
+ * slugs, SKUs, product ids, and variant ids without requiring a package release.
8
+ * Keep these primitives format-bound, not enum-bound.
9
+ */
10
+ /** @beta */
11
+ export const catalogSlugFormat = /^[a-z0-9][a-z0-9_-]*$/;
12
+ /** @beta */
13
+ export const slugSchema = z.string().min(1).max(64).regex(catalogSlugFormat);
14
+ /**
15
+ * A purchasable SKU. Charset and length are bounded, but the schema does not
16
+ * encode packaging, weight, brand, or merchant-specific prefixes.
17
+ */
18
+ /** @beta */
19
+ export const skuSchema = z
20
+ .string()
21
+ .trim()
22
+ .min(1)
23
+ .max(64)
24
+ .regex(/^[A-Za-z0-9][A-Za-z0-9._-]*$/);
25
+ /**
26
+ * A catalog product id. Accepts static ids and database ids as long as their
27
+ * shape is bounded; existence is checked by the host catalog data source.
28
+ */
29
+ /** @beta */
30
+ export const catalogProductIdSchema = z
31
+ .string()
32
+ .trim()
33
+ .min(1)
34
+ .max(64)
35
+ .regex(/^[A-Za-z0-9][A-Za-z0-9_-]*$/);
36
+ /**
37
+ * A variant id. Accepts static ids and database ids without requiring a literal
38
+ * prefix owned by the package.
39
+ */
40
+ /** @beta */
41
+ export const variantIdSchema = z
42
+ .string()
43
+ .trim()
44
+ .min(1)
45
+ .max(64)
46
+ .regex(/^[A-Za-z0-9][A-Za-z0-9_-]*$/);
@@ -0,0 +1,2 @@
1
+ /** @beta */
2
+ export * from "./identifiers.js";
@@ -0,0 +1,2 @@
1
+ /** @beta */
2
+ export * from "./identifiers.js";
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Reference checkout idempotency-key contract.
3
+ *
4
+ * This module validates the shape of a header-bound idempotency key only. The
5
+ * current product checkout validates body `intent.idempotencyKey`, not this
6
+ * header contract; downstream checkout runtimes must explicitly wire this
7
+ * helper before treating the header as authoritative.
8
+ *
9
+ * Callers own any persistence workflow for inserting, replaying, or completing
10
+ * a checkout idempotency record.
11
+ */
12
+ /** @beta */
13
+ export declare const CHECKOUT_IDEMPOTENCY_KEY_HEADER = "idempotency-key";
14
+ /** @beta */
15
+ export type CheckoutIdempotencyRejection = {
16
+ reason: "missing";
17
+ message: string;
18
+ } | {
19
+ reason: "malformed";
20
+ message: string;
21
+ };
22
+ /** @beta */
23
+ export declare function validateCheckoutIdempotencyHeader(headerValue: string | undefined | null): {
24
+ ok: true;
25
+ key: string;
26
+ } | {
27
+ ok: false;
28
+ rejection: CheckoutIdempotencyRejection;
29
+ };
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Reference checkout idempotency-key contract.
3
+ *
4
+ * This module validates the shape of a header-bound idempotency key only. The
5
+ * current product checkout validates body `intent.idempotencyKey`, not this
6
+ * header contract; downstream checkout runtimes must explicitly wire this
7
+ * helper before treating the header as authoritative.
8
+ *
9
+ * Callers own any persistence workflow for inserting, replaying, or completing
10
+ * a checkout idempotency record.
11
+ */
12
+ /** @beta */
13
+ export const CHECKOUT_IDEMPOTENCY_KEY_HEADER = "idempotency-key";
14
+ const UUID_V4_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
15
+ /** @beta */
16
+ export function validateCheckoutIdempotencyHeader(headerValue) {
17
+ if (headerValue === undefined || headerValue === null || headerValue.trim().length === 0) {
18
+ return {
19
+ ok: false,
20
+ rejection: {
21
+ reason: "missing",
22
+ message: `Missing required ${CHECKOUT_IDEMPOTENCY_KEY_HEADER} header.`,
23
+ },
24
+ };
25
+ }
26
+ const trimmed = headerValue.trim();
27
+ if (!UUID_V4_PATTERN.test(trimmed)) {
28
+ return {
29
+ ok: false,
30
+ rejection: {
31
+ reason: "malformed",
32
+ message: `${CHECKOUT_IDEMPOTENCY_KEY_HEADER} must be a UUID v4.`,
33
+ },
34
+ };
35
+ }
36
+ return { ok: true, key: trimmed };
37
+ }
@@ -0,0 +1,2 @@
1
+ /** @beta */
2
+ export * from "./idempotency.js";
@@ -0,0 +1,2 @@
1
+ /** @beta */
2
+ export * from "./idempotency.js";
@@ -0,0 +1,220 @@
1
+ import { z } from "zod";
2
+ /** @beta */
3
+ export declare const COMPANY_IDENTITY_CONTRACT_VERSION: "company_identity.lookup.v1";
4
+ /** Why the lookup is being performed — lets an adapter apply purpose-specific
5
+ * policy (e.g. stricter verification for a checkout invoice than for a saved
6
+ * billing profile). */
7
+ /** @beta */
8
+ export declare const companyIdentityPurposeSchema: z.ZodEnum<{
9
+ checkout_invoice: "checkout_invoice";
10
+ customer_billing_profile: "customer_billing_profile";
11
+ }>;
12
+ /**
13
+ * How much the returned company data can be trusted:
14
+ * - `registry_verified` — confirmed against an authoritative registry;
15
+ * - `provider_verified` — confirmed via a commercial data provider (weaker);
16
+ * - `manual_unverified` — supplied by the user, not checked;
17
+ * - `invalid` — the identifier failed format/existence checks.
18
+ */
19
+ /** @beta */
20
+ export declare const companyIdentityVerificationLevelSchema: z.ZodEnum<{
21
+ registry_verified: "registry_verified";
22
+ provider_verified: "provider_verified";
23
+ manual_unverified: "manual_unverified";
24
+ invalid: "invalid";
25
+ }>;
26
+ /**
27
+ * Outcome of a lookup. Distinguishes "no data" reasons so callers branch on
28
+ * data, not exceptions:
29
+ * - `found` — a single company resolved;
30
+ * - `not_found` — identifier valid but no record;
31
+ * - `partial` — some fields resolved, others missing;
32
+ * - `invalid` — identifier failed format/checksum;
33
+ * - `ambiguous` — more than one candidate;
34
+ * - `unsupported_country` — no adapter for this country;
35
+ * - `provider_unavailable` — transient upstream failure (retryable).
36
+ */
37
+ /** @beta */
38
+ export declare const companyIdentityLookupStatusSchema: z.ZodEnum<{
39
+ partial: "partial";
40
+ invalid: "invalid";
41
+ found: "found";
42
+ not_found: "not_found";
43
+ ambiguous: "ambiguous";
44
+ unsupported_country: "unsupported_country";
45
+ provider_unavailable: "provider_unavailable";
46
+ }>;
47
+ /** Per-source outcome inside a lookup (a lookup may consult several sources).
48
+ * Same vocabulary as the overall status minus the request-level
49
+ * `unsupported_country`, which is decided before any source is queried. */
50
+ /** @beta */
51
+ export declare const companyIdentitySourceStatusSchema: z.ZodEnum<{
52
+ partial: "partial";
53
+ invalid: "invalid";
54
+ found: "found";
55
+ not_found: "not_found";
56
+ ambiguous: "ambiguous";
57
+ provider_unavailable: "provider_unavailable";
58
+ }>;
59
+ /** Open, format-validated identifier kind (e.g. a national tax-id scheme key).
60
+ * Deliberately NOT a closed enum: the neutral core does not enumerate
61
+ * country-specific schemes — the host adapter decides which kinds it accepts. */
62
+ /** @beta */
63
+ export declare const companyIdentityIdentifierKindSchema: z.ZodString;
64
+ /** @beta */
65
+ export declare const companyIdentityAddressSchema: z.ZodObject<{
66
+ line1: z.ZodString;
67
+ postalCode: z.ZodString;
68
+ city: z.ZodString;
69
+ country: z.ZodString;
70
+ }, z.core.$strict>;
71
+ /** @beta */
72
+ export declare const companyIdentityCompanySchema: z.ZodObject<{
73
+ country: z.ZodString;
74
+ identifierKind: z.ZodString;
75
+ identifierValue: z.ZodString;
76
+ legalName: z.ZodNullable<z.ZodString>;
77
+ registeredAddress: z.ZodNullable<z.ZodObject<{
78
+ line1: z.ZodString;
79
+ postalCode: z.ZodString;
80
+ city: z.ZodString;
81
+ country: z.ZodString;
82
+ }, z.core.$strict>>;
83
+ registryStatus: z.ZodNullable<z.ZodString>;
84
+ }, z.core.$strict>;
85
+ /** @beta */
86
+ export declare const companyIdentitySourceSchema: z.ZodObject<{
87
+ providerKind: z.ZodString;
88
+ status: z.ZodEnum<{
89
+ partial: "partial";
90
+ invalid: "invalid";
91
+ found: "found";
92
+ not_found: "not_found";
93
+ ambiguous: "ambiguous";
94
+ provider_unavailable: "provider_unavailable";
95
+ }>;
96
+ observedAt: z.ZodString;
97
+ evidenceHash: z.ZodNullable<z.ZodString>;
98
+ }, z.core.$strict>;
99
+ /** Lookup coordinates with optional manual identity for registry reconciliation.
100
+ * Country is an open ISO-3166 alpha-2 code. Parsing uppercases country and
101
+ * lowercases identifier kind; national tax-id rules belong to extensions. */
102
+ /** @beta */
103
+ export declare const companyIdentityLookupRequestSchema: z.ZodPipe<z.ZodObject<{
104
+ country: z.ZodString;
105
+ identifierKind: z.ZodString;
106
+ identifierValue: z.ZodString;
107
+ purpose: z.ZodEnum<{
108
+ checkout_invoice: "checkout_invoice";
109
+ customer_billing_profile: "customer_billing_profile";
110
+ }>;
111
+ manualCompany: z.ZodOptional<z.ZodObject<{
112
+ country: z.ZodOptional<z.ZodString>;
113
+ identifierKind: z.ZodOptional<z.ZodString>;
114
+ identifierValue: z.ZodOptional<z.ZodString>;
115
+ legalName: z.ZodNullable<z.ZodString>;
116
+ registeredAddress: z.ZodNullable<z.ZodObject<{
117
+ line1: z.ZodString;
118
+ postalCode: z.ZodString;
119
+ city: z.ZodString;
120
+ country: z.ZodString;
121
+ }, z.core.$strict>>;
122
+ registryStatus: z.ZodOptional<z.ZodNullable<z.ZodString>>;
123
+ }, z.core.$strict>>;
124
+ }, z.core.$strict>, z.ZodTransform<NormalizableCompanyIdentityLookupRequest, {
125
+ country: string;
126
+ identifierKind: string;
127
+ identifierValue: string;
128
+ purpose: "checkout_invoice" | "customer_billing_profile";
129
+ manualCompany?: {
130
+ legalName: string | null;
131
+ registeredAddress: {
132
+ line1: string;
133
+ postalCode: string;
134
+ city: string;
135
+ country: string;
136
+ } | null;
137
+ country?: string | undefined;
138
+ identifierKind?: string | undefined;
139
+ identifierValue?: string | undefined;
140
+ registryStatus?: string | null | undefined;
141
+ } | undefined;
142
+ }>>;
143
+ /** A lookup result. `status` + `verificationLevel` say what happened and how
144
+ * trustworthy it is; `company` is null unless resolved; `sources` records each
145
+ * consulted provider's per-source outcome; `warnings` carries non-fatal notes. */
146
+ /** @beta */
147
+ export declare const companyIdentityLookupResponseSchema: z.ZodObject<{
148
+ contractVersion: z.ZodLiteral<"company_identity.lookup.v1">;
149
+ status: z.ZodEnum<{
150
+ partial: "partial";
151
+ invalid: "invalid";
152
+ found: "found";
153
+ not_found: "not_found";
154
+ ambiguous: "ambiguous";
155
+ unsupported_country: "unsupported_country";
156
+ provider_unavailable: "provider_unavailable";
157
+ }>;
158
+ verificationLevel: z.ZodEnum<{
159
+ registry_verified: "registry_verified";
160
+ provider_verified: "provider_verified";
161
+ manual_unverified: "manual_unverified";
162
+ invalid: "invalid";
163
+ }>;
164
+ company: z.ZodNullable<z.ZodObject<{
165
+ country: z.ZodString;
166
+ identifierKind: z.ZodString;
167
+ identifierValue: z.ZodString;
168
+ legalName: z.ZodNullable<z.ZodString>;
169
+ registeredAddress: z.ZodNullable<z.ZodObject<{
170
+ line1: z.ZodString;
171
+ postalCode: z.ZodString;
172
+ city: z.ZodString;
173
+ country: z.ZodString;
174
+ }, z.core.$strict>>;
175
+ registryStatus: z.ZodNullable<z.ZodString>;
176
+ }, z.core.$strict>>;
177
+ sources: z.ZodArray<z.ZodObject<{
178
+ providerKind: z.ZodString;
179
+ status: z.ZodEnum<{
180
+ partial: "partial";
181
+ invalid: "invalid";
182
+ found: "found";
183
+ not_found: "not_found";
184
+ ambiguous: "ambiguous";
185
+ provider_unavailable: "provider_unavailable";
186
+ }>;
187
+ observedAt: z.ZodString;
188
+ evidenceHash: z.ZodNullable<z.ZodString>;
189
+ }, z.core.$strict>>;
190
+ warnings: z.ZodDefault<z.ZodArray<z.ZodString>>;
191
+ }, z.core.$strict>;
192
+ /** @beta */
193
+ export type CompanyIdentityLookupRequest = z.infer<typeof companyIdentityLookupRequestSchema>;
194
+ /** @beta */
195
+ export type CompanyIdentityLookupResponse = z.infer<typeof companyIdentityLookupResponseSchema>;
196
+ /** @beta */
197
+ export type CompanyIdentityCompany = z.infer<typeof companyIdentityCompanySchema>;
198
+ /** @beta */
199
+ export type CompanyIdentityPurpose = z.infer<typeof companyIdentityPurposeSchema>;
200
+ /** @beta */
201
+ export type CompanyIdentitySource = z.infer<typeof companyIdentitySourceSchema>;
202
+ /** @beta */
203
+ export type CompanyIdentitySourceStatus = z.infer<typeof companyIdentitySourceStatusSchema>;
204
+ /** @beta */
205
+ export type CompanyIdentityVerificationLevel = z.infer<typeof companyIdentityVerificationLevelSchema>;
206
+ interface NormalizableCompanyIdentityLookupRequest {
207
+ country: string;
208
+ identifierKind: string;
209
+ identifierValue: string;
210
+ purpose: CompanyIdentityPurpose;
211
+ manualCompany?: Partial<CompanyIdentityCompany>;
212
+ }
213
+ /** @beta */
214
+ export declare function normalizeCompanyIdentityLookupRequest(request: NormalizableCompanyIdentityLookupRequest): NormalizableCompanyIdentityLookupRequest;
215
+ /** True when the company has the minimum fields needed to render/persist a full
216
+ * billing identity: legal name plus a complete registered address. Used to gate
217
+ * whether a `partial` lookup is usable for its purpose. */
218
+ /** @beta */
219
+ export declare function isCompleteCompanyIdentity(company: CompanyIdentityCompany | null): boolean;
220
+ export {};
@@ -0,0 +1,167 @@
1
+ import { z } from "zod";
2
+ /** @beta */
3
+ export const COMPANY_IDENTITY_CONTRACT_VERSION = "company_identity.lookup.v1";
4
+ /** Why the lookup is being performed — lets an adapter apply purpose-specific
5
+ * policy (e.g. stricter verification for a checkout invoice than for a saved
6
+ * billing profile). */
7
+ /** @beta */
8
+ export const companyIdentityPurposeSchema = z.enum([
9
+ "checkout_invoice",
10
+ "customer_billing_profile",
11
+ ]);
12
+ /**
13
+ * How much the returned company data can be trusted:
14
+ * - `registry_verified` — confirmed against an authoritative registry;
15
+ * - `provider_verified` — confirmed via a commercial data provider (weaker);
16
+ * - `manual_unverified` — supplied by the user, not checked;
17
+ * - `invalid` — the identifier failed format/existence checks.
18
+ */
19
+ /** @beta */
20
+ export const companyIdentityVerificationLevelSchema = z.enum([
21
+ "registry_verified",
22
+ "provider_verified",
23
+ "manual_unverified",
24
+ "invalid",
25
+ ]);
26
+ /**
27
+ * Outcome of a lookup. Distinguishes "no data" reasons so callers branch on
28
+ * data, not exceptions:
29
+ * - `found` — a single company resolved;
30
+ * - `not_found` — identifier valid but no record;
31
+ * - `partial` — some fields resolved, others missing;
32
+ * - `invalid` — identifier failed format/checksum;
33
+ * - `ambiguous` — more than one candidate;
34
+ * - `unsupported_country` — no adapter for this country;
35
+ * - `provider_unavailable` — transient upstream failure (retryable).
36
+ */
37
+ /** @beta */
38
+ export const companyIdentityLookupStatusSchema = z.enum([
39
+ "found",
40
+ "not_found",
41
+ "partial",
42
+ "invalid",
43
+ "ambiguous",
44
+ "unsupported_country",
45
+ "provider_unavailable",
46
+ ]);
47
+ /** Per-source outcome inside a lookup (a lookup may consult several sources).
48
+ * Same vocabulary as the overall status minus the request-level
49
+ * `unsupported_country`, which is decided before any source is queried. */
50
+ /** @beta */
51
+ export const companyIdentitySourceStatusSchema = z.enum([
52
+ "found",
53
+ "not_found",
54
+ "partial",
55
+ "invalid",
56
+ "ambiguous",
57
+ "provider_unavailable",
58
+ ]);
59
+ /** Open, format-validated identifier kind (e.g. a national tax-id scheme key).
60
+ * Deliberately NOT a closed enum: the neutral core does not enumerate
61
+ * country-specific schemes — the host adapter decides which kinds it accepts. */
62
+ /** @beta */
63
+ export const companyIdentityIdentifierKindSchema = z
64
+ .string()
65
+ .trim()
66
+ .toLowerCase()
67
+ .min(1)
68
+ .max(80)
69
+ .regex(/^[a-z0-9_:-]+$/);
70
+ /** @beta */
71
+ export const companyIdentityAddressSchema = z
72
+ .object({
73
+ line1: z.string().trim().min(1).max(240),
74
+ postalCode: z.string().trim().min(1).max(16),
75
+ city: z.string().trim().min(1).max(120),
76
+ country: z.string().trim().toUpperCase().length(2),
77
+ })
78
+ .strict();
79
+ /** @beta */
80
+ export const companyIdentityCompanySchema = z
81
+ .object({
82
+ country: z.string().trim().toUpperCase().length(2),
83
+ identifierKind: companyIdentityIdentifierKindSchema,
84
+ identifierValue: z.string().trim().min(1).max(80),
85
+ legalName: z.string().trim().min(1).max(240).nullable(),
86
+ registeredAddress: companyIdentityAddressSchema.nullable(),
87
+ registryStatus: z.string().trim().min(1).max(80).nullable(),
88
+ })
89
+ .strict();
90
+ /** @beta */
91
+ export const companyIdentitySourceSchema = z
92
+ .object({
93
+ providerKind: z.string().trim().min(1).max(120),
94
+ status: companyIdentitySourceStatusSchema,
95
+ observedAt: z.string().datetime({ offset: true }),
96
+ evidenceHash: z.string().trim().min(8).max(160).nullable(),
97
+ })
98
+ .strict();
99
+ /** Lookup coordinates with optional manual identity for registry reconciliation.
100
+ * Country is an open ISO-3166 alpha-2 code. Parsing uppercases country and
101
+ * lowercases identifier kind; national tax-id rules belong to extensions. */
102
+ /** @beta */
103
+ export const companyIdentityLookupRequestSchema = z
104
+ .object({
105
+ country: z.string().trim().toUpperCase().length(2),
106
+ identifierKind: companyIdentityIdentifierKindSchema,
107
+ identifierValue: z.string().trim().min(1).max(120),
108
+ purpose: companyIdentityPurposeSchema,
109
+ manualCompany: companyIdentityCompanySchema.partial({
110
+ identifierKind: true,
111
+ identifierValue: true,
112
+ country: true,
113
+ registryStatus: true,
114
+ }).optional(),
115
+ })
116
+ .strict()
117
+ .transform((request) => normalizeCompanyIdentityLookupRequest(request));
118
+ /** A lookup result. `status` + `verificationLevel` say what happened and how
119
+ * trustworthy it is; `company` is null unless resolved; `sources` records each
120
+ * consulted provider's per-source outcome; `warnings` carries non-fatal notes. */
121
+ /** @beta */
122
+ export const companyIdentityLookupResponseSchema = z
123
+ .object({
124
+ contractVersion: z.literal(COMPANY_IDENTITY_CONTRACT_VERSION),
125
+ status: companyIdentityLookupStatusSchema,
126
+ verificationLevel: companyIdentityVerificationLevelSchema,
127
+ company: companyIdentityCompanySchema.nullable(),
128
+ sources: z.array(companyIdentitySourceSchema),
129
+ warnings: z.array(z.string().trim().min(1).max(120)).default([]),
130
+ })
131
+ .strict();
132
+ /** @beta */
133
+ export function normalizeCompanyIdentityLookupRequest(request) {
134
+ const country = String(request.country).trim().toUpperCase();
135
+ const identifierKind = String(request.identifierKind).trim().toLowerCase();
136
+ const identifierValue = request.identifierValue.trim();
137
+ const normalized = {
138
+ country,
139
+ identifierKind,
140
+ identifierValue,
141
+ purpose: request.purpose,
142
+ };
143
+ if (request.manualCompany) {
144
+ return {
145
+ ...normalized,
146
+ manualCompany: {
147
+ ...request.manualCompany,
148
+ country,
149
+ identifierKind,
150
+ identifierValue,
151
+ registryStatus: request.manualCompany.registryStatus ?? "manual",
152
+ },
153
+ };
154
+ }
155
+ return normalized;
156
+ }
157
+ /** True when the company has the minimum fields needed to render/persist a full
158
+ * billing identity: legal name plus a complete registered address. Used to gate
159
+ * whether a `partial` lookup is usable for its purpose. */
160
+ /** @beta */
161
+ export function isCompleteCompanyIdentity(company) {
162
+ return Boolean(company?.legalName &&
163
+ company.registeredAddress?.line1 &&
164
+ company.registeredAddress.postalCode &&
165
+ company.registeredAddress.city &&
166
+ company.registeredAddress.country);
167
+ }
@@ -0,0 +1,6 @@
1
+ /** @beta */
2
+ export { COMPANY_IDENTITY_CONTRACT_VERSION, companyIdentityAddressSchema, companyIdentityCompanySchema, companyIdentityIdentifierKindSchema, companyIdentityLookupRequestSchema, companyIdentityLookupResponseSchema, companyIdentityLookupStatusSchema, companyIdentityPurposeSchema, companyIdentitySourceSchema, companyIdentitySourceStatusSchema, companyIdentityVerificationLevelSchema, isCompleteCompanyIdentity, normalizeCompanyIdentityLookupRequest, } from "./contracts.js";
3
+ /** @beta */
4
+ export type { CompanyIdentityCompany, CompanyIdentityLookupRequest, CompanyIdentityLookupResponse, CompanyIdentityPurpose, CompanyIdentitySource, CompanyIdentitySourceStatus, CompanyIdentityVerificationLevel, } from "./contracts.js";
5
+ /** @beta */
6
+ export type { CompanyIdentityLookupPort } from "./ports.js";
@@ -0,0 +1,2 @@
1
+ /** @beta */
2
+ export { COMPANY_IDENTITY_CONTRACT_VERSION, companyIdentityAddressSchema, companyIdentityCompanySchema, companyIdentityIdentifierKindSchema, companyIdentityLookupRequestSchema, companyIdentityLookupResponseSchema, companyIdentityLookupStatusSchema, companyIdentityPurposeSchema, companyIdentitySourceSchema, companyIdentitySourceStatusSchema, companyIdentityVerificationLevelSchema, isCompleteCompanyIdentity, normalizeCompanyIdentityLookupRequest, } from "./contracts.js";
@@ -0,0 +1,13 @@
1
+ import type { CompanyIdentityLookupRequest, CompanyIdentityLookupResponse } from "./contracts.js";
2
+ /**
3
+ * Provider seam for resolving a company's registry identity from a tax/registry
4
+ * identifier. The host application supplies the adapter (a national registry
5
+ * client, a commercial data provider, or a manual store); the core owns only
6
+ * this request/response contract. Adapters must not throw on a "not found" or
7
+ * "unsupported country" outcome — those are represented in the response
8
+ * `status`, so callers can branch on data rather than exceptions.
9
+ */
10
+ /** @beta */
11
+ export interface CompanyIdentityLookupPort {
12
+ lookupCompanyIdentity(request: CompanyIdentityLookupRequest): Promise<CompanyIdentityLookupResponse>;
13
+ }
@@ -0,0 +1 @@
1
+ export {};