@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.
- package/CHANGELOG.md +225 -0
- package/CODE_OF_CONDUCT.md +39 -0
- package/CONTRIBUTING.md +34 -0
- package/LICENSE +204 -0
- package/MAINTAINERS.md +33 -0
- package/README.md +85 -3
- package/SECURITY.md +29 -0
- package/dist/bundle/contracts.d.ts +9 -0
- package/dist/bundle/contracts.js +1 -0
- package/dist/bundle/ports.d.ts +41 -0
- package/dist/bundle/ports.js +1 -0
- package/dist/catalog/identifiers.d.ts +31 -0
- package/dist/catalog/identifiers.js +46 -0
- package/dist/catalog/index.d.ts +2 -0
- package/dist/catalog/index.js +2 -0
- package/dist/checkout/idempotency.d.ts +29 -0
- package/dist/checkout/idempotency.js +37 -0
- package/dist/checkout/index.d.ts +2 -0
- package/dist/checkout/index.js +2 -0
- package/dist/company-identity/contracts.d.ts +220 -0
- package/dist/company-identity/contracts.js +167 -0
- package/dist/company-identity/index.d.ts +6 -0
- package/dist/company-identity/index.js +2 -0
- package/dist/company-identity/ports.d.ts +13 -0
- package/dist/company-identity/ports.js +1 -0
- package/dist/fulfillment/facts.d.ts +103 -0
- package/dist/fulfillment/facts.js +195 -0
- package/dist/fulfillment/index.d.ts +4 -0
- package/dist/fulfillment/index.js +2 -0
- package/dist/inventory/atp.d.ts +172 -0
- package/dist/inventory/atp.js +211 -0
- package/dist/inventory/index.d.ts +2 -0
- package/dist/inventory/index.js +2 -0
- package/dist/marketing/research/contracts.d.ts +75 -0
- package/dist/marketing/research/contracts.js +60 -0
- package/dist/marketing/research/index.d.ts +4 -0
- package/dist/marketing/research/index.js +4 -0
- package/dist/marketing/research/ports.d.ts +15 -0
- package/dist/marketing/research/ports.js +1 -0
- package/dist/partners/index.d.ts +4 -0
- package/dist/partners/index.js +4 -0
- package/dist/partners/ports.d.ts +12 -0
- package/dist/partners/ports.js +1 -0
- package/dist/partners/status.d.ts +48 -0
- package/dist/partners/status.js +35 -0
- package/dist/payment/executionBaseContracts.d.ts +81 -0
- package/dist/payment/executionBaseContracts.js +8 -0
- package/dist/payment/index.d.ts +36 -0
- package/dist/payment/index.js +18 -0
- package/dist/payment/methodLifecycle.d.ts +91 -0
- package/dist/payment/methodLifecycle.js +76 -0
- package/dist/payment/paymentControlTypes.d.ts +135 -0
- package/dist/payment/paymentControlTypes.js +110 -0
- package/dist/payment/paymentFailureTaxonomy.d.ts +80 -0
- package/dist/payment/paymentFailureTaxonomy.js +155 -0
- package/dist/payment/paymentFailureTaxonomyContracts.d.ts +106 -0
- package/dist/payment/paymentFailureTaxonomyContracts.js +177 -0
- package/dist/payment/paymentRecovery.d.ts +26 -0
- package/dist/payment/paymentRecovery.js +73 -0
- package/dist/payment/paymentRecoveryContracts.d.ts +53 -0
- package/dist/payment/paymentRecoveryContracts.js +10 -0
- package/dist/payment/paymentStateMachine.d.ts +28 -0
- package/dist/payment/paymentStateMachine.js +184 -0
- package/dist/payment/providerAttemptIdempotency.d.ts +23 -0
- package/dist/payment/providerAttemptIdempotency.js +31 -0
- package/dist/payment/providerCapability.d.ts +148 -0
- package/dist/payment/providerCapability.js +13 -0
- package/dist/platform-runtime/contracts.d.ts +9 -0
- package/dist/platform-runtime/contracts.js +13 -0
- package/dist/platform-runtime/index.d.ts +10 -0
- package/dist/platform-runtime/index.js +4 -0
- package/dist/platform-runtime/platformKernel.d.ts +44 -0
- package/dist/platform-runtime/platformKernel.js +39 -0
- package/dist/platform-runtime/ports.d.ts +100 -0
- package/dist/platform-runtime/ports.js +1 -0
- package/dist/pricing/index.d.ts +8 -0
- package/dist/pricing/index.js +8 -0
- package/dist/pricing/ports.d.ts +22 -0
- package/dist/pricing/ports.js +7 -0
- package/dist/pricing/pricingBreakdown.d.ts +86 -0
- package/dist/pricing/pricingBreakdown.js +155 -0
- package/dist/pricing/targetPriceAllocation.d.ts +97 -0
- package/dist/pricing/targetPriceAllocation.js +202 -0
- package/dist/pricing/types.d.ts +32 -0
- package/dist/pricing/types.js +4 -0
- package/dist/promo/adjustmentEngine.d.ts +4 -0
- package/dist/promo/adjustmentEngine.js +194 -0
- package/dist/promo/adjustmentTypes.d.ts +103 -0
- package/dist/promo/adjustmentTypes.js +13 -0
- package/dist/promo/index.d.ts +8 -0
- package/dist/promo/index.js +8 -0
- package/dist/promo/promoEvaluator.d.ts +25 -0
- package/dist/promo/promoEvaluator.js +135 -0
- package/dist/promo/types.d.ts +86 -0
- package/dist/promo/types.js +12 -0
- package/dist/risk/core/evaluator.d.ts +3 -0
- package/dist/risk/core/evaluator.js +32 -0
- package/dist/risk/core/rules.d.ts +3 -0
- package/dist/risk/core/rules.js +118 -0
- package/dist/risk/core/types.d.ts +65 -0
- package/dist/risk/core/types.js +1 -0
- package/dist/risk/index.d.ts +8 -0
- package/dist/risk/index.js +8 -0
- package/dist/risk/types.d.ts +32 -0
- package/dist/risk/types.js +43 -0
- package/dist/shipping/index.d.ts +4 -0
- package/dist/shipping/index.js +4 -0
- package/dist/shipping/shippingResolver.d.ts +26 -0
- package/dist/shipping/shippingResolver.js +88 -0
- package/dist/shipping/types.d.ts +45 -0
- package/dist/shipping/types.js +4 -0
- package/dist/subscription/cycleHardening.d.ts +95 -0
- package/dist/subscription/cycleHardening.js +118 -0
- package/dist/subscription/index.d.ts +14 -0
- package/dist/subscription/index.js +14 -0
- package/dist/subscription/subscriptionEngineCore.d.ts +13 -0
- package/dist/subscription/subscriptionEngineCore.js +145 -0
- package/dist/subscription/subscriptionEngineLifecycle.d.ts +150 -0
- package/dist/subscription/subscriptionEngineLifecycle.js +433 -0
- package/dist/subscription/subscriptionEnginePayment.d.ts +25 -0
- package/dist/subscription/subscriptionEnginePayment.js +127 -0
- package/dist/subscription/subscriptionEngineTypes.d.ts +94 -0
- package/dist/subscription/subscriptionEngineTypes.js +4 -0
- package/dist/subscription/subscriptionEngineUtils.d.ts +32 -0
- package/dist/subscription/subscriptionEngineUtils.js +74 -0
- package/dist/subscription/types.d.ts +58 -0
- package/dist/subscription/types.js +47 -0
- package/dist/testing.d.ts +48 -0
- package/dist/testing.js +105 -0
- package/package.json +215 -4
- package/release-gates.json +232 -0
- package/src/bundle/contracts.ts +15 -0
- package/src/bundle/ports.ts +32 -0
- package/src/catalog/identifiers.ts +50 -0
- package/src/catalog/index.ts +2 -0
- package/src/checkout/idempotency.ts +49 -0
- package/src/checkout/index.ts +2 -0
- package/src/company-identity/contracts.ts +208 -0
- package/src/company-identity/index.ts +28 -0
- package/src/company-identity/ports.ts +19 -0
- package/src/fulfillment/facts.ts +300 -0
- package/src/fulfillment/index.ts +34 -0
- package/src/inventory/atp.ts +249 -0
- package/src/inventory/index.ts +2 -0
- package/src/marketing/research/contracts.ts +91 -0
- package/src/marketing/research/index.ts +4 -0
- package/src/marketing/research/ports.ts +26 -0
- package/src/partners/index.ts +4 -0
- package/src/partners/ports.ts +18 -0
- package/src/partners/status.ts +49 -0
- package/src/payment/executionBaseContracts.ts +93 -0
- package/src/payment/index.ts +128 -0
- package/src/payment/methodLifecycle.ts +130 -0
- package/src/payment/paymentControlTypes.ts +197 -0
- package/src/payment/paymentFailureTaxonomy.ts +201 -0
- package/src/payment/paymentFailureTaxonomyContracts.ts +228 -0
- package/src/payment/paymentRecovery.ts +95 -0
- package/src/payment/paymentRecoveryContracts.ts +61 -0
- package/src/payment/paymentStateMachine.ts +263 -0
- package/src/payment/providerAttemptIdempotency.ts +57 -0
- package/src/payment/providerCapability.ts +172 -0
- package/src/platform-runtime/contracts.ts +33 -0
- package/src/platform-runtime/index.ts +36 -0
- package/src/platform-runtime/platformKernel.ts +86 -0
- package/src/platform-runtime/ports.ts +88 -0
- package/src/pricing/index.ts +8 -0
- package/src/pricing/ports.ts +27 -0
- package/src/pricing/pricingBreakdown.ts +243 -0
- package/src/pricing/targetPriceAllocation.ts +293 -0
- package/src/pricing/types.ts +36 -0
- package/src/promo/adjustmentEngine.ts +253 -0
- package/src/promo/adjustmentTypes.ts +94 -0
- package/src/promo/index.ts +8 -0
- package/src/promo/promoEvaluator.ts +137 -0
- package/src/promo/types.ts +97 -0
- package/src/risk/core/evaluator.ts +41 -0
- package/src/risk/core/rules.ts +128 -0
- package/src/risk/core/types.ts +73 -0
- package/src/risk/index.ts +8 -0
- package/src/risk/types.ts +60 -0
- package/src/shipping/index.ts +4 -0
- package/src/shipping/shippingResolver.ts +101 -0
- package/src/shipping/types.ts +49 -0
- package/src/subscription/cycleHardening.ts +174 -0
- package/src/subscription/index.ts +14 -0
- package/src/subscription/subscriptionEngineCore.ts +181 -0
- package/src/subscription/subscriptionEngineLifecycle.ts +574 -0
- package/src/subscription/subscriptionEnginePayment.ts +179 -0
- package/src/subscription/subscriptionEngineTypes.ts +114 -0
- package/src/subscription/subscriptionEngineUtils.ts +110 -0
- package/src/subscription/types.ts +104 -0
- 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,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,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 {};
|