@vxil/cli 0.36.0 → 0.36.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -73,6 +73,24 @@ export declare const SNS_TOPIC_ARN_PATTERN = "^arn:aws(-[a-z]+)?:sns:[a-z0-9-]+:
73
73
  * a list so a newly launched SES region needs no vxil release; a typo still
74
74
  * fails at `vxil push` (TypeBox), never as a DNS error on the first send. */
75
75
  export declare const SES_REGION_PATTERN = "^[a-z]{2}(-[a-z]+)+-\\d$";
76
+ /** (w45 W44-WEBHOOK-SECRETREF-PATTERN) the ONE pattern every webhook secret
77
+ * ref shares (notifications `webhookSecretRef`, payments `stripe` / `paddle`
78
+ * / `revenuecat` `webhookSecretRef`): a secret-store name, letters, digits or
79
+ * '_', at most 64, with the optional `secret:` prefix both resolvers strip
80
+ * (payments-v1 resolveProviderSecrets, notifications-v1
81
+ * resolveTenantSecretRef). Stored secret names are lowercase-only
82
+ * (control-plane SECRET_NAME_RE), so both resolvers LOWERCASE the name after
83
+ * the strip: a capital ref reads its lowercase row. Upper case is accepted
84
+ * (founder decision D-k2-1 option (a), parked; built per the w45 brief) so
85
+ * this pattern refuses no stored config: the w45 read-only count found
86
+ * stored refs with capitals on staging, which never resolved before the
87
+ * lowercasing (so they were not live). A typo shape (a space, '-', '.', a
88
+ * path, an empty or over-long name) is refused at push instead of failing
89
+ * closed only when a webhook arrives. */
90
+ export declare const WEBHOOK_SECRET_REF_PATTERN = "^(secret:)?[A-Za-z0-9_]{1,64}$";
91
+ /** The validator's message for a ref that misses WEBHOOK_SECRET_REF_PATTERN
92
+ * (TypeBox's own reads "Expected string to match '…'"). */
93
+ export declare const WEBHOOK_SECRET_REF_MESSAGE = "a secret ref is the name of a stored secret: lowercase letters, numbers or '_' (capitals are read as lowercase), at most 64 characters, optionally prefixed 'secret:'";
76
94
  export declare const NotificationsConfigSchema: import("@sinclair/typebox").TObject<{
77
95
  enabled: import("@sinclair/typebox").TBoolean;
78
96
  fromEmail: import("@sinclair/typebox").TString;
@@ -834,6 +852,7 @@ export declare const PaymentsConfigSchema: import("@sinclair/typebox").TObject<{
834
852
  webhookSecretRef: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
835
853
  acceptSandbox: import("@sinclair/typebox").TBoolean;
836
854
  sandboxUsers: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
855
+ testStore: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"accept">, import("@sinclair/typebox").TLiteral<"reject">]>>;
837
856
  }>>;
838
857
  paypal: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
839
858
  clientIdRef: import("@sinclair/typebox").TString;
package/dist/vxil-main.js CHANGED
@@ -5322,7 +5322,7 @@ function isDeclaredOnOwnerErase(v) {
5322
5322
  function onOwnerEraseWidens(declared, remote) {
5323
5323
  return declared === "delete" && remote !== "delete";
5324
5324
  }
5325
- var FN_RETRY_MAX_ATTEMPTS, FN_FORWARD_HEADERS_MAX, FN_SERVER_SCOPES_MAX, NOTIF_OVERRIDE_SUBJECT_MAX, NOTIF_OVERRIDE_BODY_MAX, NOTIF_OVERRIDE_MAX_BYTES, SNS_TOPIC_ARN_PATTERN, SES_REGION_PATTERN, NotificationsConfigSchema, GENERATION_DEFAULTS, GENERATION_BOUNDS, JobsConfigSchema, OAuthRefsSchema, AppleRefsSchema, OidcProviderSchema, REDIRECT_ORIGIN_PATTERN, AuthConfigSchema, RL_POLICY_NAME_PATTERN, RL_MAX_DECLARED_POLICIES, DeclaredRlPolicySchema, RateLimitsConfigSchema, FilesConfigSchema, DeclaredWebhookSubscriptionSchema, WebhooksConfigSchema, CommentsConfigSchema, CMS_MAX_COLLECTIONS_CEILING, CMS_QUERY_DEFAULTS, CmsConfigSchema, McpConfigSchema, RealtimeConfigSchema, PresenceConfigSchema, DeclaredOrgRoleSchema, OrgsConfigSchema, ActivityFeedConfigSchema, SEARCH_COLLECTION_DECLARED_CAP, SEARCH_COLLECTION_DIMS, DeclaredSearchCollectionSchema, HybridLaneWeights, VectorSearchConfigSchema, AI_TEMPLATE_NAME_PATTERN, AI_MAX_DECLARED_TEMPLATES, DeclaredAiTemplateSchema, AiConfigSchema, RagConfigSchema, PaymentsConfigSchema, FunctionsConfigSchema, CopilotConfigSchema, DENY_FUNCTION_SCOPES, FEATURE_KEYS, CMS_RETAIN_DAYS_MAX, CMS_DELETED_RETAIN_DAYS_MAX, CMS_DELETED_RETAIN_DAYS_DEFAULT;
5325
+ var FN_RETRY_MAX_ATTEMPTS, FN_FORWARD_HEADERS_MAX, FN_SERVER_SCOPES_MAX, NOTIF_OVERRIDE_SUBJECT_MAX, NOTIF_OVERRIDE_BODY_MAX, NOTIF_OVERRIDE_MAX_BYTES, SNS_TOPIC_ARN_PATTERN, SES_REGION_PATTERN, WEBHOOK_SECRET_REF_PATTERN, webhookSecretRef, NotificationsConfigSchema, GENERATION_DEFAULTS, GENERATION_BOUNDS, JobsConfigSchema, OAuthRefsSchema, AppleRefsSchema, OidcProviderSchema, REDIRECT_ORIGIN_PATTERN, AuthConfigSchema, RL_POLICY_NAME_PATTERN, RL_MAX_DECLARED_POLICIES, DeclaredRlPolicySchema, RateLimitsConfigSchema, FilesConfigSchema, DeclaredWebhookSubscriptionSchema, WebhooksConfigSchema, CommentsConfigSchema, CMS_MAX_COLLECTIONS_CEILING, CMS_QUERY_DEFAULTS, CmsConfigSchema, McpConfigSchema, RealtimeConfigSchema, PresenceConfigSchema, DeclaredOrgRoleSchema, OrgsConfigSchema, ActivityFeedConfigSchema, SEARCH_COLLECTION_DECLARED_CAP, SEARCH_COLLECTION_DIMS, DeclaredSearchCollectionSchema, HybridLaneWeights, VectorSearchConfigSchema, AI_TEMPLATE_NAME_PATTERN, AI_MAX_DECLARED_TEMPLATES, DeclaredAiTemplateSchema, AiConfigSchema, RagConfigSchema, PaymentsConfigSchema, FunctionsConfigSchema, CopilotConfigSchema, DENY_FUNCTION_SCOPES, FEATURE_KEYS, CMS_RETAIN_DAYS_MAX, CMS_DELETED_RETAIN_DAYS_MAX, CMS_DELETED_RETAIN_DAYS_DEFAULT;
5326
5326
  var init_src = __esm({
5327
5327
  "../feature-configs/src/index.ts"() {
5328
5328
  "use strict";
@@ -5354,6 +5354,8 @@ var init_src = __esm({
5354
5354
  NOTIF_OVERRIDE_MAX_BYTES = 64 * 1024;
5355
5355
  SNS_TOPIC_ARN_PATTERN = "^arn:aws(-[a-z]+)?:sns:[a-z0-9-]+:\\d{12}:[A-Za-z0-9_-]{1,256}$";
5356
5356
  SES_REGION_PATTERN = "^[a-z]{2}(-[a-z]+)+-\\d$";
5357
+ WEBHOOK_SECRET_REF_PATTERN = "^(secret:)?[A-Za-z0-9_]{1,64}$";
5358
+ webhookSecretRef = () => Type.String({ pattern: WEBHOOK_SECRET_REF_PATTERN });
5357
5359
  NotificationsConfigSchema = Type.Object({
5358
5360
  enabled: Type.Boolean({ default: true }),
5359
5361
  fromEmail: Type.String({ format: "email" }),
@@ -5369,7 +5371,7 @@ var init_src = __esm({
5369
5371
  // instead of the platform-wide PROVIDER_WEBHOOK_SECRET, binding the signature
5370
5372
  // to the tenant so a signed event for tenant A can never validate at tenant
5371
5373
  // B's webhook URL (mirrors payments revenuecat.webhookSecretRef).
5372
- webhookSecretRef: Type.Optional(Type.String()),
5374
+ webhookSecretRef: Type.Optional(webhookSecretRef()),
5373
5375
  // 'mock' exists for staging/e2e (deterministic provider); 'resend' is MVP;
5374
5376
  // 'ses' (2026-09-19) is the second real provider — Amazon SES v2, BYO IAM
5375
5377
  // keys, same delivery/suppression/preference pipeline as resend.
@@ -6722,12 +6724,12 @@ var init_src = __esm({
6722
6724
  // "configure it or not", not each inner ref — guide ch. 6, auth).
6723
6725
  stripe: Type.Optional(Type.Object({
6724
6726
  secretKeyRef: Type.String(),
6725
- webhookSecretRef: Type.String(),
6727
+ webhookSecretRef: webhookSecretRef(),
6726
6728
  taxEnabled: Type.Boolean({ default: false })
6727
6729
  })),
6728
6730
  paddle: Type.Optional(Type.Object({
6729
6731
  apiKeyRef: Type.String(),
6730
- webhookSecretRef: Type.String(),
6732
+ webhookSecretRef: webhookSecretRef(),
6731
6733
  sandbox: Type.Boolean({ default: false })
6732
6734
  })),
6733
6735
  revenuecat: Type.Optional(Type.Object({
@@ -6743,7 +6745,7 @@ var init_src = __esm({
6743
6745
  // verification, it fails CLOSED: every delivery is 401 bad_signature with a
6744
6746
  // `sig_failed` row that can never be reprocessed. Mirrors stripe/paddle
6745
6747
  // webhookSecretRef.
6746
- webhookSecretRef: Type.Optional(Type.String()),
6748
+ webhookSecretRef: Type.Optional(webhookSecretRef()),
6747
6749
  // Environment integrity. RevenueCat posts SANDBOX
6748
6750
  // and PRODUCTION events to the SAME webhook with the same auth header, so a
6749
6751
  // sandbox purchase would otherwise fold into production entitlements. A
@@ -6761,7 +6763,19 @@ var init_src = __esm({
6761
6763
  // TestFlight purchase and is refused by the CLI's production promotion
6762
6764
  // gate). No default on purpose (Value.Default would materialize it into
6763
6765
  // every RC manifest); absent = an empty list.
6764
- sandboxUsers: Type.Optional(Type.Array(Type.String({ minLength: 1, maxLength: 256 }), { maxItems: 20 }))
6766
+ sandboxUsers: Type.Optional(Type.Array(Type.String({ minLength: 1, maxLength: 256 }), { maxItems: 20 })),
6767
+ // (2026-11-03) RevenueCat Test Store purchases.
6768
+ // A Test Store purchase is SANDBOX data that needs no store account,
6769
+ // invite or license tester (anyone with the app's public `test_` key can
6770
+ // make one), so `acceptSandbox: true` on a production project would fold
6771
+ // it. 'reject' refuses every delivery whose RAW RevenueCat event says
6772
+ // `store: TEST_STORE` (and every sync/restore snapshot from the Test
6773
+ // Store) BEFORE any other environment rule, `sandboxUsers` included: the
6774
+ // delivery is kept as outcome 'rejected_test_store' (200, never folded).
6775
+ // Absent = 'accept' (today's behaviour). No schema default on purpose
6776
+ // (the sandboxUsers rule: Value.Default would materialize it into every RC
6777
+ // manifest); the reader (payments-v1 environmentAccepted) owns the default.
6778
+ testStore: Type.Optional(Type.Union([Type.Literal("accept"), Type.Literal("reject")]))
6765
6779
  })),
6766
6780
  paypal: Type.Optional(Type.Object({
6767
6781
  clientIdRef: Type.String(),
@@ -9031,9 +9045,9 @@ var init_lib = __esm({
9031
9045
  timeoutMs: { min: 1e3, max: 12e4 }
9032
9046
  };
9033
9047
  CONFIG_FILENAMES = ["vxil.config.ts", "vxil.config.mjs", "vxil.config.js"];
9034
- VXIL_CONFIG_PKG_VERSION = "0.26.1";
9035
- VXIL_SDK_PKG_VERSION = "0.35.2";
9036
- VXIL_CLI_PKG_VERSION = "0.36.0";
9048
+ VXIL_CONFIG_PKG_VERSION = "0.27.0";
9049
+ VXIL_SDK_PKG_VERSION = "0.35.3";
9050
+ VXIL_CLI_PKG_VERSION = "0.36.1";
9037
9051
  SCAFFOLD_NODE_TYPES_RANGE = "^24.0.0";
9038
9052
  SCAFFOLD_TSCONFIG = {
9039
9053
  compilerOptions: {
@@ -13341,7 +13355,7 @@ function promotionRefusals(cfg, allowed) {
13341
13355
  out.push({
13342
13356
  kind: "sandbox",
13343
13357
  flag: PROMOTION_OVERRIDE_FLAGS.sandbox,
13344
- message: `sandbox provider flags [${sandboxes.join(", ")}] would ship to a live money path (a sandbox key signs with the wrong secret; revenuecat.acceptSandbox folds EVERY TestFlight / test-track purchase into live entitlements \u2014 for store review, list the reviewer app_user_ids in revenuecat.sandboxUsers instead, which a production push allows). Set them false, or override with --${PROMOTION_OVERRIDE_FLAGS.sandbox}.`
13358
+ message: `sandbox provider flags [${sandboxes.join(", ")}] would ship to a live money path (a sandbox key signs with the wrong secret; revenuecat.acceptSandbox folds EVERY TestFlight / test-track purchase into live entitlements \u2014 for store review, list the reviewer app_user_ids in revenuecat.sandboxUsers instead, which a production push allows; if you override it for testers, also set revenuecat.testStore: 'reject', or anyone with the Test Store key folds a purchase). Set them false, or override with --${PROMOTION_OVERRIDE_FLAGS.sandbox}.`
13345
13359
  });
13346
13360
  }
13347
13361
  const devOrigins = devRedirectOrigins(redirectOrigins(cfg));
@@ -17505,13 +17519,13 @@ var TOOLS = [
17505
17519
  {
17506
17520
  name: "payments_list_webhook_events",
17507
17521
  feature: "payments",
17508
- description: "List provider webhook deliveries from the event log, newest-first: outcome (received|processed|error|sig_failed|parse_failed|reprocessed|ignored|unowned|rejected_environment), the provider-reported environment (production|sandbox), signature status, error, and timestamps per delivery. Use it to diagnose billing sync issues (e.g. an unmapped price or product, or a RevenueCat entitlement id that is not a ledger.tierMap key (with no ledger.priceMap hit) \u2192 outcome error, a misconfigured webhook secret producing sig_failed rows, sandbox deliveries landing as rejected_environment). An unmapped one-off product lands `error` unless you set ledger.unmappedProduct:'ignore', which lands it `ignored` instead. Read-only \u2014 needs payments:read. Server-side key only (403 server_only on a thin-client/end-user key) \u2014 the log is tenant-wide and carries provider payloads. Payloads are detail-only (console surface).",
17522
+ description: "List provider webhook deliveries from the event log, newest-first: outcome (received|processed|error|sig_failed|parse_failed|reprocessed|ignored|unowned|rejected_environment|rejected_test_store), the provider-reported environment (production|sandbox), signature status, error, and timestamps per delivery. Use it to diagnose billing sync issues (e.g. an unmapped price or product, or a RevenueCat entitlement id that is not a ledger.tierMap key (with no ledger.priceMap hit) \u2192 outcome error, a misconfigured webhook secret producing sig_failed rows, sandbox deliveries landing as rejected_environment, RevenueCat Test Store purchases refused under revenuecat.testStore 'reject' landing as rejected_test_store). An unmapped one-off product lands `error` unless you set ledger.unmappedProduct:'ignore', which lands it `ignored` instead. Read-only \u2014 needs payments:read. Server-side key only (403 server_only on a thin-client/end-user key) \u2014 the log is tenant-wide and carries provider payloads. Payloads are detail-only (console surface).",
17509
17523
  inputSchema: {
17510
17524
  type: "object",
17511
17525
  properties: {
17512
17526
  provider: { type: "string", enum: ["mock", "stripe", "paddle", "revenuecat", "paypal"] },
17513
17527
  event_type: { type: "string", description: "Exact event type filter, e.g. 'subscription.updated'." },
17514
- outcome: { type: "string", enum: ["received", "processed", "error", "sig_failed", "parse_failed", "reprocessed", "ignored", "unowned", "rejected_environment"] },
17528
+ outcome: { type: "string", enum: ["received", "processed", "error", "sig_failed", "parse_failed", "reprocessed", "ignored", "unowned", "rejected_environment", "rejected_test_store"] },
17515
17529
  environment: { type: "string", enum: ["production", "sandbox"], description: "The provider-reported environment of the delivery (a separate axis from the API key label)." },
17516
17530
  provider_charge_id: { type: "string", maxLength: 200, description: "Exact match on the normalised charge id (the same provider_charge_id a payments.charge.* event carries): the delivery that recorded that charge plus any refund/dispute against it \u2014 usually one row, so ONE detail read (GET /v1/payments/webhook-events/{eventId}) fetches the verified payload. Rows received before 2026-09-19 carry no charge id." },
17517
17531
  provider_evt_id: { type: "string", maxLength: 200, description: "Exact match on the provider's own event id (the provider_evt_id every row shows)." },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vxil/cli",
3
- "version": "0.36.0",
3
+ "version": "0.36.1",
4
4
  "private": false,
5
5
  "description": "The vxil CLI — init, quickstart, push, gen, secrets, keys, migrate, doctor, diff, functions, payments; installs the `vxil` command (npm i -g @vxil/cli).",
6
6
  "license": "MIT",
@@ -45,8 +45,8 @@
45
45
  }
46
46
  },
47
47
  "devDependencies": {
48
- "@vxil/config": "0.26.1",
49
- "@vxil/feature-configs": "0.23.2",
48
+ "@vxil/config": "0.27.0",
49
+ "@vxil/feature-configs": "0.24.0",
50
50
  "@vxil/runtime": "0.0.1",
51
51
  "@vxil/types": "0.0.1",
52
52
  "miniflare": "^4.20260730.0"