node-type-registry 0.36.0 → 0.38.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 (133) hide show
  1. package/blueprint-types.generated.d.ts +46 -7
  2. package/codegen/generate-types.js +40 -4
  3. package/conditions/index.d.ts +1 -0
  4. package/conditions/index.js +8 -0
  5. package/conditions/trigger-condition.d.ts +35 -0
  6. package/conditions/trigger-condition.js +97 -0
  7. package/data/index.d.ts +0 -10
  8. package/data/index.js +1 -21
  9. package/data/search-unified.js +8 -0
  10. package/data/search-vector.js +12 -0
  11. package/esm/blueprint-types.generated.d.ts +46 -7
  12. package/esm/codegen/generate-types.js +40 -4
  13. package/esm/conditions/index.d.ts +1 -0
  14. package/esm/conditions/index.js +1 -0
  15. package/esm/conditions/trigger-condition.d.ts +35 -0
  16. package/esm/conditions/trigger-condition.js +94 -0
  17. package/esm/data/index.d.ts +0 -10
  18. package/esm/data/index.js +0 -10
  19. package/esm/data/search-unified.js +8 -0
  20. package/esm/data/search-vector.js +12 -0
  21. package/esm/event/index.d.ts +2 -0
  22. package/esm/event/index.js +2 -0
  23. package/esm/event/referral.d.ts +2 -0
  24. package/esm/event/referral.js +62 -0
  25. package/esm/event/tracker.d.ts +2 -0
  26. package/esm/event/tracker.js +71 -0
  27. package/esm/index.d.ts +5 -0
  28. package/esm/index.js +13 -0
  29. package/esm/job/index.d.ts +1 -0
  30. package/esm/job/index.js +1 -0
  31. package/esm/{data/data-job-trigger.js → job/trigger.js} +3 -53
  32. package/esm/limit/enforce-aggregate.d.ts +2 -0
  33. package/esm/{data/data-aggregate-limit-counter.js → limit/enforce-aggregate.js} +6 -6
  34. package/esm/limit/enforce-counter.d.ts +2 -0
  35. package/esm/{data/data-limit-counter.js → limit/enforce-counter.js} +6 -6
  36. package/esm/limit/enforce-feature.d.ts +2 -0
  37. package/esm/{data/data-feature-flag.js → limit/enforce-feature.js} +6 -6
  38. package/esm/limit/enforce-rate.d.ts +2 -0
  39. package/esm/limit/enforce-rate.js +39 -0
  40. package/esm/limit/index.d.ts +8 -0
  41. package/esm/limit/index.js +8 -0
  42. package/esm/limit/track-usage.d.ts +2 -0
  43. package/esm/{data/data-billing-meter.js → limit/track-usage.js} +6 -6
  44. package/esm/limit/warning-aggregate.d.ts +2 -0
  45. package/esm/limit/warning-aggregate.js +24 -0
  46. package/esm/limit/warning-counter.d.ts +2 -0
  47. package/esm/limit/warning-counter.js +30 -0
  48. package/esm/limit/warning-rate.d.ts +2 -0
  49. package/esm/limit/warning-rate.js +30 -0
  50. package/esm/module-presets/auth-email-magic.js +2 -2
  51. package/esm/module-presets/auth-email.js +5 -5
  52. package/esm/module-presets/auth-hardened.js +2 -2
  53. package/esm/module-presets/auth-passkey.js +2 -2
  54. package/esm/module-presets/auth-sso.d.ts +1 -1
  55. package/esm/module-presets/auth-sso.js +5 -5
  56. package/esm/module-presets/b2b-storage.js +6 -6
  57. package/esm/module-presets/b2b.js +2 -2
  58. package/esm/module-presets/minimal.d.ts +1 -1
  59. package/esm/module-presets/minimal.js +3 -3
  60. package/esm/{data/data-chunks.js → process/chunks.js} +19 -0
  61. package/esm/{data/process-extraction.js → process/extraction.js} +15 -10
  62. package/esm/{data/data-file-embedding.js → process/file-embedding.js} +22 -10
  63. package/esm/{data/data-image-embedding.js → process/image-embedding.js} +15 -9
  64. package/esm/{data/process-image-versions.js → process/image-versions.js} +3 -9
  65. package/esm/process/index.d.ts +5 -0
  66. package/esm/process/index.js +5 -0
  67. package/event/index.d.ts +2 -0
  68. package/event/index.js +7 -0
  69. package/event/referral.d.ts +2 -0
  70. package/event/referral.js +65 -0
  71. package/event/tracker.d.ts +2 -0
  72. package/event/tracker.js +74 -0
  73. package/index.d.ts +5 -0
  74. package/index.js +13 -0
  75. package/job/index.d.ts +1 -0
  76. package/job/index.js +5 -0
  77. package/{data/data-job-trigger.js → job/trigger.js} +3 -53
  78. package/limit/enforce-aggregate.d.ts +2 -0
  79. package/{data/data-aggregate-limit-counter.js → limit/enforce-aggregate.js} +7 -7
  80. package/limit/enforce-counter.d.ts +2 -0
  81. package/{data/data-limit-counter.js → limit/enforce-counter.js} +7 -7
  82. package/limit/enforce-feature.d.ts +2 -0
  83. package/{data/data-feature-flag.js → limit/enforce-feature.js} +7 -7
  84. package/limit/enforce-rate.d.ts +2 -0
  85. package/limit/enforce-rate.js +42 -0
  86. package/limit/index.d.ts +8 -0
  87. package/limit/index.js +19 -0
  88. package/limit/track-usage.d.ts +2 -0
  89. package/{data/data-billing-meter.js → limit/track-usage.js} +7 -7
  90. package/limit/warning-aggregate.d.ts +2 -0
  91. package/limit/warning-aggregate.js +27 -0
  92. package/limit/warning-counter.d.ts +2 -0
  93. package/limit/warning-counter.js +33 -0
  94. package/limit/warning-rate.d.ts +2 -0
  95. package/limit/warning-rate.js +33 -0
  96. package/module-presets/auth-email-magic.js +2 -2
  97. package/module-presets/auth-email.js +5 -5
  98. package/module-presets/auth-hardened.js +2 -2
  99. package/module-presets/auth-passkey.js +2 -2
  100. package/module-presets/auth-sso.d.ts +1 -1
  101. package/module-presets/auth-sso.js +5 -5
  102. package/module-presets/b2b-storage.js +6 -6
  103. package/module-presets/b2b.js +2 -2
  104. package/module-presets/minimal.d.ts +1 -1
  105. package/module-presets/minimal.js +3 -3
  106. package/package.json +2 -2
  107. package/{data/data-chunks.js → process/chunks.js} +19 -0
  108. package/{data/process-extraction.js → process/extraction.js} +15 -10
  109. package/{data/data-file-embedding.js → process/file-embedding.js} +22 -10
  110. package/{data/data-image-embedding.js → process/image-embedding.js} +15 -9
  111. package/{data/process-image-versions.js → process/image-versions.js} +3 -9
  112. package/process/index.d.ts +5 -0
  113. package/process/index.js +13 -0
  114. package/data/data-aggregate-limit-counter.d.ts +0 -2
  115. package/data/data-billing-meter.d.ts +0 -2
  116. package/data/data-feature-flag.d.ts +0 -2
  117. package/data/data-limit-counter.d.ts +0 -2
  118. package/esm/data/data-aggregate-limit-counter.d.ts +0 -2
  119. package/esm/data/data-billing-meter.d.ts +0 -2
  120. package/esm/data/data-feature-flag.d.ts +0 -2
  121. package/esm/data/data-limit-counter.d.ts +0 -2
  122. /package/{data/data-job-trigger.d.ts → esm/job/trigger.d.ts} +0 -0
  123. /package/{data/data-chunks.d.ts → esm/process/chunks.d.ts} +0 -0
  124. /package/{data/process-extraction.d.ts → esm/process/extraction.d.ts} +0 -0
  125. /package/{data/data-file-embedding.d.ts → esm/process/file-embedding.d.ts} +0 -0
  126. /package/{data/data-image-embedding.d.ts → esm/process/image-embedding.d.ts} +0 -0
  127. /package/{data/process-image-versions.d.ts → esm/process/image-versions.d.ts} +0 -0
  128. /package/{esm/data/data-job-trigger.d.ts → job/trigger.d.ts} +0 -0
  129. /package/{esm/data/data-chunks.d.ts → process/chunks.d.ts} +0 -0
  130. /package/{esm/data/process-extraction.d.ts → process/extraction.d.ts} +0 -0
  131. /package/{esm/data/data-file-embedding.d.ts → process/file-embedding.d.ts} +0 -0
  132. /package/{esm/data/data-image-embedding.d.ts → process/image-embedding.d.ts} +0 -0
  133. /package/{esm/data/process-image-versions.d.ts → process/image-versions.d.ts} +0 -0
@@ -810,7 +810,9 @@ export interface BlueprintBucketSeed {
810
810
  }
811
811
  /** Storage configuration for an entity type. Seeds initial buckets, overrides module-level settings (expiry times, file size limits, CORS), and provides per-table provisioning overrides via provisions. */
812
812
  export interface BlueprintStorageConfig {
813
- /** Initial bucket seed entries. Each creates a row in {prefix}_buckets during provisioning. Only used for app-level storage (not entity-scoped). */
813
+ /** Discriminator for multi-module storage. Defaults to "default" (omitted from table names). Non-default keys appear as an infix: {prefix}_{storage_key}_buckets. Max 16 chars, lowercase snake_case. */
814
+ storage_key?: string;
815
+ /** Initial bucket seed entries. Each creates a row in {prefix}_buckets during provisioning. */
814
816
  buckets?: BlueprintBucketSeed[];
815
817
  /** Override for presigned upload URL expiry time in seconds. */
816
818
  upload_url_expiry_seconds?: number;
@@ -830,6 +832,41 @@ export interface BlueprintStorageConfig {
830
832
  buckets?: BlueprintEntityTableProvision;
831
833
  };
832
834
  }
835
+ /** A requirement entry within a blueprint achievement. Defines what events must occur to earn the achievement. */
836
+ export interface BlueprintAchievementRequirement {
837
+ /** Name identifier matching an event_type or step name. */
838
+ event_name: string;
839
+ /** Number of events needed to satisfy this requirement. */
840
+ count: number;
841
+ /** Human-readable description of what this requirement entails. */
842
+ description?: string;
843
+ }
844
+ /** A reward entry within a blueprint achievement. Defines credits granted when the achievement is earned. */
845
+ export interface BlueprintAchievementReward {
846
+ /** Type of reward: limit_credit (grants limit credits) or meter_credit (grants meter credits). */
847
+ reward_type: 'limit_credit' | 'meter_credit';
848
+ /** Target limit name or meter slug for the credit grant. */
849
+ target_name: string;
850
+ /** Number of credits to grant. */
851
+ amount: number;
852
+ /** Credit type: permanent, expiring, etc. Defaults to "permanent". */
853
+ credit_type?: string;
854
+ }
855
+ /** An achievement entry for the blueprint achievements[] section. Creates a level with requirements and optional rewards in the events_module. Requires events_module to be provisioned (e.g., via entity_types[].has_levels = true or modules includes events_module). */
856
+ export interface BlueprintAchievement {
857
+ /** Unique name for the achievement level. */
858
+ name: string;
859
+ /** Human-readable description of this achievement. */
860
+ description?: string;
861
+ /** Display ordering priority; lower values appear first. Defaults to 100. */
862
+ priority?: number;
863
+ /** Requirements that must be met to earn this achievement. */
864
+ requirements: BlueprintAchievementRequirement[];
865
+ /** Rewards granted when the achievement is earned. */
866
+ rewards?: BlueprintAchievementReward[];
867
+ /** Entity prefix to scope this achievement to (e.g., "org", "app"). Used to resolve the correct events_module. Defaults to "app". */
868
+ entity_prefix?: string;
869
+ }
833
870
  /** Override object for the entity table created by a BlueprintEntityType. Shape mirrors BlueprintTable / secure_table_provision vocabulary. When supplied, policies[] replaces the default entity-table policies entirely. */
834
871
  export interface BlueprintEntityTableProvision {
835
872
  /** Whether to enable RLS on the entity table. Forwarded to secure_table_provision. Defaults to true. */
@@ -866,16 +903,16 @@ export interface BlueprintEntityType {
866
903
  has_profiles?: boolean;
867
904
  /** Whether to provision a levels module for this entity type. Defaults to false. */
868
905
  has_levels?: boolean;
869
- /** Whether to provision a storage module (buckets, files tables) for this entity type. Defaults to false. */
870
- has_storage?: boolean;
871
906
  /** Whether to provision entity-scoped invite tables ({prefix}_invites, {prefix}_claimed_invites) and a submit_{prefix}_invite_code() function. Defaults to false. */
872
907
  has_invites?: boolean;
908
+ /** Whether to auto-attach an EventTracker to the claimed_invites table for invite-based achievements. Requires has_invites=true AND has_levels=true. When true, records 'invite_claimed' events credited to the sender (inviter) on each claimed invite. Defaults to false. */
909
+ has_invite_achievements?: boolean;
873
910
  /** Escape hatch: when true AND table_provision is NULL, zero policies are provisioned on the entity table. Defaults to false. */
874
911
  skip_entity_policies?: boolean;
875
912
  /** Override for the entity table. Shape mirrors BlueprintTable / secure_table_provision vocabulary. When supplied, its policies[] replaces the five default entity-table policies; is_visible becomes a no-op. When NULL (default), the five default policies are applied (gated by is_visible). */
876
913
  table_provision?: BlueprintEntityTableProvision;
877
- /** Storage configuration. Only used when has_storage is true. Controls RLS policies on storage tables, seeds initial buckets, and overrides module-level settings (expiry times, file size limits, CORS). */
878
- storage?: BlueprintStorageConfig;
914
+ /** Storage configuration (array-only). A non-empty array enables storage provisioning. Each entry creates a separate storage module with its own tables ({prefix}_{storage_key}_buckets/files). Controls RLS policies, bucket seeding, and module-level settings. */
915
+ storage?: BlueprintStorageConfig[];
879
916
  }
880
917
  /** String shorthand -- just the node type name. */
881
918
  export type BlueprintNodeShorthand = 'AuthzAllowAll' | 'AuthzAppMembership' | 'AuthzComposite' | 'AuthzDenyAll' | 'AuthzFilePath' | 'AuthzDirectOwner' | 'AuthzDirectOwnerAny' | 'AuthzEntityMembership' | 'AuthzMemberList' | 'AuthzNotReadOnly' | 'AuthzOrgHierarchy' | 'AuthzPeerOwnership' | 'AuthzPublishable' | 'AuthzRelatedEntityMembership' | 'AuthzRelatedMemberList' | 'AuthzRelatedPeerOwnership' | 'AuthzTemporal' | 'CheckGreaterThan' | 'CheckLessThan' | 'CheckNotEqual' | 'CheckOneOf' | 'LimitAggregate' | 'BillingMeter' | 'DataBulk' | 'ProcessChunks' | 'DataCompositeField' | 'DataDirectOwner' | 'DataEntityMembership' | 'ProcessFileEmbedding' | 'LimitFeatureFlag' | 'DataForceCurrentUser' | 'DataId' | 'ProcessImageEmbedding' | 'DataImmutableFields' | 'DataInflection' | 'DataInheritFromParent' | 'JobTrigger' | 'LimitCounter' | 'DataJsonb' | 'DataOwnedFields' | 'ProcessExtraction' | 'ProcessImageVersions' | 'DataOwnershipInEntity' | 'DataPeoplestamps' | 'DataPublishable' | 'DataRealtime' | 'DataSlug' | 'DataSoftDelete' | 'DataStatusField' | 'DataTags' | 'DataTimestamps' | 'SearchBm25' | 'SearchFullText' | 'SearchSpatial' | 'SearchSpatialAggregate' | 'SearchTrgm' | 'SearchUnified' | 'SearchVector' | 'TableOrganizationSettings' | 'TableUserProfiles' | 'TableUserSettings';
@@ -1140,6 +1177,8 @@ export interface BlueprintDefinition {
1140
1177
  unique_constraints?: BlueprintUniqueConstraint[];
1141
1178
  /** Entity types to provision in Phase 0 (before tables). Each entry creates an entity table with membership modules and security. */
1142
1179
  entity_types?: BlueprintEntityType[];
1143
- /** App-level storage configuration. Creates a storage_module (membership_type = NULL), seeds initial buckets, and overrides module-level settings (expiry times, file size limits, CORS). Use provisions for per-table policy overrides. For entity-scoped storage, use entity_types[].has_storage + entity_types[].storage instead. */
1144
- storage?: BlueprintStorageConfig;
1180
+ /** App-level storage configuration (array-only). Creates storage_module(s) (membership_type = NULL), seeds initial buckets, and overrides module-level settings. Each entry creates a separate storage module. For entity-scoped storage, use entity_types[].storage instead. */
1181
+ storage?: BlueprintStorageConfig[];
1182
+ /** Achievement definitions. Each entry creates a level with requirements and optional rewards in the events_module. Requires events_module to be provisioned (e.g., via entity_types[].has_levels = true or modules includes events_module). */
1183
+ achievements?: BlueprintAchievement[];
1145
1184
  }
@@ -515,7 +515,8 @@ function buildBlueprintBucketSeed() {
515
515
  */
516
516
  function buildBlueprintStorageConfig() {
517
517
  return addJSDoc(exportInterface('BlueprintStorageConfig', [
518
- addJSDoc(optionalProp('buckets', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintBucketSeed')))), 'Initial bucket seed entries. Each creates a row in {prefix}_buckets during provisioning. Only used for app-level storage (not entity-scoped).'),
518
+ addJSDoc(optionalProp('storage_key', t.tsStringKeyword()), 'Discriminator for multi-module storage. Defaults to "default" (omitted from table names). Non-default keys appear as an infix: {prefix}_{storage_key}_buckets. Max 16 chars, lowercase snake_case.'),
519
+ addJSDoc(optionalProp('buckets', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintBucketSeed')))), 'Initial bucket seed entries. Each creates a row in {prefix}_buckets during provisioning.'),
519
520
  addJSDoc(optionalProp('upload_url_expiry_seconds', t.tsNumberKeyword()), 'Override for presigned upload URL expiry time in seconds.'),
520
521
  addJSDoc(optionalProp('download_url_expiry_seconds', t.tsNumberKeyword()), 'Override for presigned download URL expiry time in seconds.'),
521
522
  addJSDoc(optionalProp('default_max_file_size', t.tsNumberKeyword()), 'Default maximum file size in bytes for the storage module.'),
@@ -528,6 +529,37 @@ function buildBlueprintStorageConfig() {
528
529
  ])), 'Per-table overrides for storage tables. Each key targets a specific storage table (files, buckets) and uses the same shape as table_provision: { nodes, fields, grants, use_rls, policies }. Fanned out to secure_table_provision targeting the corresponding table. When a key includes policies[], those REPLACE the default storage policies for that table; tables without a key still get defaults.')
529
530
  ]), 'Storage configuration for an entity type. Seeds initial buckets, overrides module-level settings (expiry times, file size limits, CORS), and provides per-table provisioning overrides via provisions.');
530
531
  }
532
+ // ---------------------------------------------------------------------------
533
+ // Achievement types
534
+ // ---------------------------------------------------------------------------
535
+ function buildBlueprintAchievementRequirement() {
536
+ return addJSDoc(exportInterface('BlueprintAchievementRequirement', [
537
+ addJSDoc(requiredProp('event_name', t.tsStringKeyword()), 'Name identifier matching an event_type or step name.'),
538
+ addJSDoc(requiredProp('count', t.tsNumberKeyword()), 'Number of events needed to satisfy this requirement.'),
539
+ addJSDoc(optionalProp('description', t.tsStringKeyword()), 'Human-readable description of what this requirement entails.')
540
+ ]), 'A requirement entry within a blueprint achievement. Defines what events must occur to earn the achievement.');
541
+ }
542
+ function buildBlueprintAchievementReward() {
543
+ return addJSDoc(exportInterface('BlueprintAchievementReward', [
544
+ addJSDoc(requiredProp('reward_type', t.tsUnionType([
545
+ t.tsLiteralType(t.stringLiteral('limit_credit')),
546
+ t.tsLiteralType(t.stringLiteral('meter_credit'))
547
+ ])), 'Type of reward: limit_credit (grants limit credits) or meter_credit (grants meter credits).'),
548
+ addJSDoc(requiredProp('target_name', t.tsStringKeyword()), 'Target limit name or meter slug for the credit grant.'),
549
+ addJSDoc(requiredProp('amount', t.tsNumberKeyword()), 'Number of credits to grant.'),
550
+ addJSDoc(optionalProp('credit_type', t.tsStringKeyword()), 'Credit type: permanent, expiring, etc. Defaults to "permanent".')
551
+ ]), 'A reward entry within a blueprint achievement. Defines credits granted when the achievement is earned.');
552
+ }
553
+ function buildBlueprintAchievement() {
554
+ return addJSDoc(exportInterface('BlueprintAchievement', [
555
+ addJSDoc(requiredProp('name', t.tsStringKeyword()), 'Unique name for the achievement level.'),
556
+ addJSDoc(optionalProp('description', t.tsStringKeyword()), 'Human-readable description of this achievement.'),
557
+ addJSDoc(optionalProp('priority', t.tsNumberKeyword()), 'Display ordering priority; lower values appear first. Defaults to 100.'),
558
+ addJSDoc(requiredProp('requirements', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintAchievementRequirement')))), 'Requirements that must be met to earn this achievement.'),
559
+ addJSDoc(optionalProp('rewards', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintAchievementReward')))), 'Rewards granted when the achievement is earned.'),
560
+ addJSDoc(optionalProp('entity_prefix', t.tsStringKeyword()), 'Entity prefix to scope this achievement to (e.g., "org", "app"). Used to resolve the correct events_module. Defaults to "app".')
561
+ ]), 'An achievement entry for the blueprint achievements[] section. Creates a level with requirements and optional rewards in the events_module. Requires events_module to be provisioned (e.g., via entity_types[].has_levels = true or modules includes events_module).');
562
+ }
531
563
  function buildBlueprintEntityTableProvision() {
532
564
  return addJSDoc(exportInterface('BlueprintEntityTableProvision', [
533
565
  addJSDoc(optionalProp('use_rls', t.tsBooleanKeyword()), 'Whether to enable RLS on the entity table. Forwarded to secure_table_provision. Defaults to true.'),
@@ -551,11 +583,11 @@ function buildBlueprintEntityType() {
551
583
  addJSDoc(optionalProp('has_limits', t.tsBooleanKeyword()), 'Whether to provision a limits module for this entity type. Defaults to false.'),
552
584
  addJSDoc(optionalProp('has_profiles', t.tsBooleanKeyword()), 'Whether to provision a profiles module for this entity type. Defaults to false.'),
553
585
  addJSDoc(optionalProp('has_levels', t.tsBooleanKeyword()), 'Whether to provision a levels module for this entity type. Defaults to false.'),
554
- addJSDoc(optionalProp('has_storage', t.tsBooleanKeyword()), 'Whether to provision a storage module (buckets, files tables) for this entity type. Defaults to false.'),
555
586
  addJSDoc(optionalProp('has_invites', t.tsBooleanKeyword()), 'Whether to provision entity-scoped invite tables ({prefix}_invites, {prefix}_claimed_invites) and a submit_{prefix}_invite_code() function. Defaults to false.'),
587
+ addJSDoc(optionalProp('has_invite_achievements', t.tsBooleanKeyword()), "Whether to auto-attach an EventTracker to the claimed_invites table for invite-based achievements. Requires has_invites=true AND has_levels=true. When true, records 'invite_claimed' events credited to the sender (inviter) on each claimed invite. Defaults to false."),
556
588
  addJSDoc(optionalProp('skip_entity_policies', t.tsBooleanKeyword()), 'Escape hatch: when true AND table_provision is NULL, zero policies are provisioned on the entity table. Defaults to false.'),
557
589
  addJSDoc(optionalProp('table_provision', t.tsTypeReference(t.identifier('BlueprintEntityTableProvision'))), 'Override for the entity table. Shape mirrors BlueprintTable / secure_table_provision vocabulary. When supplied, its policies[] replaces the five default entity-table policies; is_visible becomes a no-op. When NULL (default), the five default policies are applied (gated by is_visible).'),
558
- addJSDoc(optionalProp('storage', t.tsTypeReference(t.identifier('BlueprintStorageConfig'))), 'Storage configuration. Only used when has_storage is true. Controls RLS policies on storage tables, seeds initial buckets, and overrides module-level settings (expiry times, file size limits, CORS).')
590
+ addJSDoc(optionalProp('storage', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintStorageConfig')))), 'Storage module configuration array. Each entry provisions a separate storage module with its own tables, RLS, and settings. When non-empty, has_storage is derived as true. Each entry may specify a storage_key for multi-module support (defaults to "default").')
559
591
  ]), 'An entity type entry for Phase 0 of construct_blueprint(). Provisions a full entity type with its own entity table, membership modules, and security policies via entity_type_provision.');
560
592
  }
561
593
  function buildBlueprintTable() {
@@ -583,7 +615,8 @@ function buildBlueprintDefinition() {
583
615
  addJSDoc(optionalProp('full_text_searches', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintFullTextSearch')))), 'Full-text search configurations.'),
584
616
  addJSDoc(optionalProp('unique_constraints', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintUniqueConstraint')))), 'Unique constraints on table columns.'),
585
617
  addJSDoc(optionalProp('entity_types', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintEntityType')))), 'Entity types to provision in Phase 0 (before tables). Each entry creates an entity table with membership modules and security.'),
586
- addJSDoc(optionalProp('storage', t.tsTypeReference(t.identifier('BlueprintStorageConfig'))), 'App-level storage configuration. Creates a storage_module (membership_type = NULL), seeds initial buckets, and overrides module-level settings (expiry times, file size limits, CORS). Use provisions for per-table policy overrides. For entity-scoped storage, use entity_types[].has_storage + entity_types[].storage instead.')
618
+ addJSDoc(optionalProp('storage', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintStorageConfig')))), 'App-level storage configuration array. Each entry creates a storage_module (membership_type = NULL) with its own tables and settings. For entity-scoped storage, use entity_types[].storage instead.'),
619
+ addJSDoc(optionalProp('achievements', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintAchievement')))), 'Achievement definitions. Each entry creates a level with requirements and optional rewards in the events_module. Requires events_module to be provisioned (e.g., via entity_types[].has_levels = true or modules includes events_module).')
587
620
  ]), 'The complete blueprint definition -- the JSONB shape accepted by construct_blueprint().');
588
621
  }
589
622
  // ---------------------------------------------------------------------------
@@ -642,6 +675,9 @@ function buildProgram(meta) {
642
675
  statements.push(buildBlueprintTableUniqueConstraint());
643
676
  statements.push(buildBlueprintBucketSeed());
644
677
  statements.push(buildBlueprintStorageConfig());
678
+ statements.push(buildBlueprintAchievementRequirement());
679
+ statements.push(buildBlueprintAchievementReward());
680
+ statements.push(buildBlueprintAchievement());
645
681
  statements.push(buildBlueprintEntityTableProvision());
646
682
  statements.push(buildBlueprintEntityType());
647
683
  // -- Node types discriminated union --
@@ -0,0 +1 @@
1
+ export { conditionDefs, conditionProperties, triggerConditionSchema, triggerConditionsProperty } from './trigger-condition';
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.triggerConditionsProperty = exports.triggerConditionSchema = exports.conditionProperties = exports.conditionDefs = void 0;
4
+ var trigger_condition_1 = require("./trigger-condition");
5
+ Object.defineProperty(exports, "conditionDefs", { enumerable: true, get: function () { return trigger_condition_1.conditionDefs; } });
6
+ Object.defineProperty(exports, "conditionProperties", { enumerable: true, get: function () { return trigger_condition_1.conditionProperties; } });
7
+ Object.defineProperty(exports, "triggerConditionSchema", { enumerable: true, get: function () { return trigger_condition_1.triggerConditionSchema; } });
8
+ Object.defineProperty(exports, "triggerConditionsProperty", { enumerable: true, get: function () { return trigger_condition_1.triggerConditionsProperty; } });
@@ -0,0 +1,35 @@
1
+ import type { JSONSchema } from '../types';
2
+ /**
3
+ * Shared trigger condition schema used by any node type that creates
4
+ * PostgreSQL triggers with conditional WHEN clauses.
5
+ *
6
+ * Consumed by: JobTrigger, EventTracker, ProcessExtraction,
7
+ * ProcessImageVersions, ProcessFileEmbedding, ProcessImageEmbedding.
8
+ *
9
+ * On the SQL side, these conditions are compiled to AST via
10
+ * metaschema_generators.build_condition_ast().
11
+ */
12
+ export declare const triggerConditionSchema: JSONSchema;
13
+ /**
14
+ * $defs block for parameter_schema. Spread into any node that uses conditions.
15
+ *
16
+ * Usage:
17
+ * parameter_schema: { type: 'object', $defs: conditionDefs, properties: { ... } }
18
+ */
19
+ export declare const conditionDefs: Record<string, JSONSchema>;
20
+ /**
21
+ * Common condition-related properties for trigger-based nodes.
22
+ * Three mutually exclusive options for WHEN clause specification.
23
+ *
24
+ * Usage:
25
+ * properties: { event_name: { ... }, ...conditionProperties }
26
+ */
27
+ export declare const conditionProperties: Record<string, JSONSchema>;
28
+ /**
29
+ * Standalone trigger_conditions property for nodes that compose on top of
30
+ * JobTrigger (Process* nodes). These use trigger_conditions instead of
31
+ * the full condition_field/conditions/watch_fields trio because the
32
+ * underlying JobTrigger handles the WHEN clause; this property adds
33
+ * additional conditions merged via AND.
34
+ */
35
+ export declare const triggerConditionsProperty: JSONSchema;
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.triggerConditionsProperty = exports.conditionProperties = exports.conditionDefs = exports.triggerConditionSchema = void 0;
4
+ /**
5
+ * Shared trigger condition schema used by any node type that creates
6
+ * PostgreSQL triggers with conditional WHEN clauses.
7
+ *
8
+ * Consumed by: JobTrigger, EventTracker, ProcessExtraction,
9
+ * ProcessImageVersions, ProcessFileEmbedding, ProcessImageEmbedding.
10
+ *
11
+ * On the SQL side, these conditions are compiled to AST via
12
+ * metaschema_generators.build_condition_ast().
13
+ */
14
+ exports.triggerConditionSchema = {
15
+ type: 'object',
16
+ description: 'A leaf condition ({field, op, value?, row?, ref?}) or a combinator ({AND, OR, NOT}).',
17
+ properties: {
18
+ field: { type: 'string', format: 'column-ref', description: 'Column name (validated against the table).' },
19
+ op: {
20
+ type: 'string',
21
+ enum: ['=', '!=', '>', '<', '>=', '<=', 'LIKE', 'NOT LIKE', 'IS NULL', 'IS NOT NULL', 'IS DISTINCT FROM'],
22
+ description: 'Comparison operator.'
23
+ },
24
+ value: { description: 'Comparison value. Type is resolved from the column definition. Omit for IS NULL, IS NOT NULL, IS DISTINCT FROM.' },
25
+ row: { type: 'string', enum: ['NEW', 'OLD'], default: 'NEW', description: 'Row reference (default: NEW).' },
26
+ ref: {
27
+ type: 'object',
28
+ description: 'Column reference for field-to-field comparison (alternative to value).',
29
+ properties: {
30
+ field: { type: 'string', format: 'column-ref' },
31
+ row: { type: 'string', enum: ['NEW', 'OLD'], default: 'NEW' }
32
+ }
33
+ },
34
+ AND: { type: 'array', description: 'Array of conditions combined with AND.', items: { $ref: '#/$defs/triggerCondition' } },
35
+ OR: { type: 'array', description: 'Array of conditions combined with OR.', items: { $ref: '#/$defs/triggerCondition' } },
36
+ NOT: { $ref: '#/$defs/triggerCondition', description: 'Negated condition.' }
37
+ }
38
+ };
39
+ /**
40
+ * $defs block for parameter_schema. Spread into any node that uses conditions.
41
+ *
42
+ * Usage:
43
+ * parameter_schema: { type: 'object', $defs: conditionDefs, properties: { ... } }
44
+ */
45
+ exports.conditionDefs = {
46
+ triggerCondition: exports.triggerConditionSchema
47
+ };
48
+ /**
49
+ * Common condition-related properties for trigger-based nodes.
50
+ * Three mutually exclusive options for WHEN clause specification.
51
+ *
52
+ * Usage:
53
+ * properties: { event_name: { ... }, ...conditionProperties }
54
+ */
55
+ exports.conditionProperties = {
56
+ condition_field: {
57
+ type: 'string',
58
+ format: 'column-ref',
59
+ description: 'Column name for conditional WHEN clause (fires only when field equals condition_value)'
60
+ },
61
+ condition_value: {
62
+ type: 'string',
63
+ description: 'Value to compare against condition_field in WHEN clause'
64
+ },
65
+ conditions: {
66
+ description: 'Compound conditions for the trigger WHEN clause. Accepts a single leaf condition, an array of conditions (implicitly AND), or a nested combinator tree ({AND: [...], OR: [...], NOT: {...}}). Each leaf is {field, op, value?, row?, ref?}. Column types are resolved automatically from the table schema. Cannot be combined with condition_field or watch_fields.',
67
+ 'x-codegen-type': 'TriggerCondition | TriggerCondition[]',
68
+ oneOf: [
69
+ { $ref: '#/$defs/triggerCondition' },
70
+ { type: 'array', items: { $ref: '#/$defs/triggerCondition' } }
71
+ ]
72
+ },
73
+ watch_fields: {
74
+ type: 'array',
75
+ items: {
76
+ type: 'string',
77
+ format: 'column-ref'
78
+ },
79
+ description: 'For UPDATE triggers, only fire when these fields change (uses DISTINCT FROM)'
80
+ }
81
+ };
82
+ /**
83
+ * Standalone trigger_conditions property for nodes that compose on top of
84
+ * JobTrigger (Process* nodes). These use trigger_conditions instead of
85
+ * the full condition_field/conditions/watch_fields trio because the
86
+ * underlying JobTrigger handles the WHEN clause; this property adds
87
+ * additional conditions merged via AND.
88
+ */
89
+ exports.triggerConditionsProperty = {
90
+ description: 'Additional compound conditions beyond auto-generated filtering. ' +
91
+ 'Merged with the auto-generated conditions via AND.',
92
+ 'x-codegen-type': 'TriggerCondition | TriggerCondition[]',
93
+ oneOf: [
94
+ { $ref: '#/$defs/triggerCondition' },
95
+ { type: 'array', items: { $ref: '#/$defs/triggerCondition' } }
96
+ ]
97
+ };
package/data/index.d.ts CHANGED
@@ -2,27 +2,17 @@ export { CheckGreaterThan } from './check-greater-than';
2
2
  export { CheckLessThan } from './check-less-than';
3
3
  export { CheckNotEqual } from './check-not-equal';
4
4
  export { CheckOneOf } from './check-one-of';
5
- export { LimitAggregate } from './data-aggregate-limit-counter';
6
- export { BillingMeter } from './data-billing-meter';
7
5
  export { DataBulk } from './data-bulk';
8
- export { ProcessChunks } from './data-chunks';
9
6
  export { DataCompositeField } from './data-composite-field';
10
7
  export { DataDirectOwner } from './data-direct-owner';
11
8
  export { DataEntityMembership } from './data-entity-membership';
12
- export { ProcessFileEmbedding } from './data-file-embedding';
13
- export { LimitFeatureFlag } from './data-feature-flag';
14
9
  export { DataForceCurrentUser } from './data-force-current-user';
15
10
  export { DataId } from './data-id';
16
- export { ProcessImageEmbedding } from './data-image-embedding';
17
11
  export { DataImmutableFields } from './data-immutable-fields';
18
12
  export { DataInflection } from './data-inflection';
19
13
  export { DataInheritFromParent } from './data-inherit-from-parent';
20
- export { JobTrigger } from './data-job-trigger';
21
- export { LimitCounter } from './data-limit-counter';
22
14
  export { DataJsonb } from './data-jsonb';
23
15
  export { DataOwnedFields } from './data-owned-fields';
24
- export { ProcessExtraction } from './process-extraction';
25
- export { ProcessImageVersions } from './process-image-versions';
26
16
  export { DataOwnershipInEntity } from './data-ownership-in-entity';
27
17
  export { DataPeoplestamps } from './data-peoplestamps';
28
18
  export { DataPublishable } from './data-publishable';
package/data/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TableUserSettings = exports.TableUserProfiles = exports.TableOrganizationSettings = exports.SearchVector = exports.SearchUnified = exports.SearchTrgm = exports.SearchSpatialAggregate = exports.SearchSpatial = exports.SearchFullText = exports.SearchBm25 = exports.DataTimestamps = exports.DataTags = exports.DataStatusField = exports.DataSoftDelete = exports.DataSlug = exports.DataRealtime = exports.DataPublishable = exports.DataPeoplestamps = exports.DataOwnershipInEntity = exports.ProcessImageVersions = exports.ProcessExtraction = exports.DataOwnedFields = exports.DataJsonb = exports.LimitCounter = exports.JobTrigger = exports.DataInheritFromParent = exports.DataInflection = exports.DataImmutableFields = exports.ProcessImageEmbedding = exports.DataId = exports.DataForceCurrentUser = exports.LimitFeatureFlag = exports.ProcessFileEmbedding = exports.DataEntityMembership = exports.DataDirectOwner = exports.DataCompositeField = exports.ProcessChunks = exports.DataBulk = exports.BillingMeter = exports.LimitAggregate = exports.CheckOneOf = exports.CheckNotEqual = exports.CheckLessThan = exports.CheckGreaterThan = void 0;
3
+ exports.TableUserSettings = exports.TableUserProfiles = exports.TableOrganizationSettings = exports.SearchVector = exports.SearchUnified = exports.SearchTrgm = exports.SearchSpatialAggregate = exports.SearchSpatial = exports.SearchFullText = exports.SearchBm25 = exports.DataTimestamps = exports.DataTags = exports.DataStatusField = exports.DataSoftDelete = exports.DataSlug = exports.DataRealtime = exports.DataPublishable = exports.DataPeoplestamps = exports.DataOwnershipInEntity = exports.DataOwnedFields = exports.DataJsonb = exports.DataInheritFromParent = exports.DataInflection = exports.DataImmutableFields = exports.DataId = exports.DataForceCurrentUser = exports.DataEntityMembership = exports.DataDirectOwner = exports.DataCompositeField = exports.DataBulk = exports.CheckOneOf = exports.CheckNotEqual = exports.CheckLessThan = exports.CheckGreaterThan = void 0;
4
4
  var check_greater_than_1 = require("./check-greater-than");
5
5
  Object.defineProperty(exports, "CheckGreaterThan", { enumerable: true, get: function () { return check_greater_than_1.CheckGreaterThan; } });
6
6
  var check_less_than_1 = require("./check-less-than");
@@ -9,48 +9,28 @@ var check_not_equal_1 = require("./check-not-equal");
9
9
  Object.defineProperty(exports, "CheckNotEqual", { enumerable: true, get: function () { return check_not_equal_1.CheckNotEqual; } });
10
10
  var check_one_of_1 = require("./check-one-of");
11
11
  Object.defineProperty(exports, "CheckOneOf", { enumerable: true, get: function () { return check_one_of_1.CheckOneOf; } });
12
- var data_aggregate_limit_counter_1 = require("./data-aggregate-limit-counter");
13
- Object.defineProperty(exports, "LimitAggregate", { enumerable: true, get: function () { return data_aggregate_limit_counter_1.LimitAggregate; } });
14
- var data_billing_meter_1 = require("./data-billing-meter");
15
- Object.defineProperty(exports, "BillingMeter", { enumerable: true, get: function () { return data_billing_meter_1.BillingMeter; } });
16
12
  var data_bulk_1 = require("./data-bulk");
17
13
  Object.defineProperty(exports, "DataBulk", { enumerable: true, get: function () { return data_bulk_1.DataBulk; } });
18
- var data_chunks_1 = require("./data-chunks");
19
- Object.defineProperty(exports, "ProcessChunks", { enumerable: true, get: function () { return data_chunks_1.ProcessChunks; } });
20
14
  var data_composite_field_1 = require("./data-composite-field");
21
15
  Object.defineProperty(exports, "DataCompositeField", { enumerable: true, get: function () { return data_composite_field_1.DataCompositeField; } });
22
16
  var data_direct_owner_1 = require("./data-direct-owner");
23
17
  Object.defineProperty(exports, "DataDirectOwner", { enumerable: true, get: function () { return data_direct_owner_1.DataDirectOwner; } });
24
18
  var data_entity_membership_1 = require("./data-entity-membership");
25
19
  Object.defineProperty(exports, "DataEntityMembership", { enumerable: true, get: function () { return data_entity_membership_1.DataEntityMembership; } });
26
- var data_file_embedding_1 = require("./data-file-embedding");
27
- Object.defineProperty(exports, "ProcessFileEmbedding", { enumerable: true, get: function () { return data_file_embedding_1.ProcessFileEmbedding; } });
28
- var data_feature_flag_1 = require("./data-feature-flag");
29
- Object.defineProperty(exports, "LimitFeatureFlag", { enumerable: true, get: function () { return data_feature_flag_1.LimitFeatureFlag; } });
30
20
  var data_force_current_user_1 = require("./data-force-current-user");
31
21
  Object.defineProperty(exports, "DataForceCurrentUser", { enumerable: true, get: function () { return data_force_current_user_1.DataForceCurrentUser; } });
32
22
  var data_id_1 = require("./data-id");
33
23
  Object.defineProperty(exports, "DataId", { enumerable: true, get: function () { return data_id_1.DataId; } });
34
- var data_image_embedding_1 = require("./data-image-embedding");
35
- Object.defineProperty(exports, "ProcessImageEmbedding", { enumerable: true, get: function () { return data_image_embedding_1.ProcessImageEmbedding; } });
36
24
  var data_immutable_fields_1 = require("./data-immutable-fields");
37
25
  Object.defineProperty(exports, "DataImmutableFields", { enumerable: true, get: function () { return data_immutable_fields_1.DataImmutableFields; } });
38
26
  var data_inflection_1 = require("./data-inflection");
39
27
  Object.defineProperty(exports, "DataInflection", { enumerable: true, get: function () { return data_inflection_1.DataInflection; } });
40
28
  var data_inherit_from_parent_1 = require("./data-inherit-from-parent");
41
29
  Object.defineProperty(exports, "DataInheritFromParent", { enumerable: true, get: function () { return data_inherit_from_parent_1.DataInheritFromParent; } });
42
- var data_job_trigger_1 = require("./data-job-trigger");
43
- Object.defineProperty(exports, "JobTrigger", { enumerable: true, get: function () { return data_job_trigger_1.JobTrigger; } });
44
- var data_limit_counter_1 = require("./data-limit-counter");
45
- Object.defineProperty(exports, "LimitCounter", { enumerable: true, get: function () { return data_limit_counter_1.LimitCounter; } });
46
30
  var data_jsonb_1 = require("./data-jsonb");
47
31
  Object.defineProperty(exports, "DataJsonb", { enumerable: true, get: function () { return data_jsonb_1.DataJsonb; } });
48
32
  var data_owned_fields_1 = require("./data-owned-fields");
49
33
  Object.defineProperty(exports, "DataOwnedFields", { enumerable: true, get: function () { return data_owned_fields_1.DataOwnedFields; } });
50
- var process_extraction_1 = require("./process-extraction");
51
- Object.defineProperty(exports, "ProcessExtraction", { enumerable: true, get: function () { return process_extraction_1.ProcessExtraction; } });
52
- var process_image_versions_1 = require("./process-image-versions");
53
- Object.defineProperty(exports, "ProcessImageVersions", { enumerable: true, get: function () { return process_image_versions_1.ProcessImageVersions; } });
54
34
  var data_ownership_in_entity_1 = require("./data-ownership-in-entity");
55
35
  Object.defineProperty(exports, "DataOwnershipInEntity", { enumerable: true, get: function () { return data_ownership_in_entity_1.DataOwnershipInEntity; } });
56
36
  var data_peoplestamps_1 = require("./data-peoplestamps");
@@ -111,6 +111,14 @@ exports.SearchUnified = {
111
111
  format: 'column-ref'
112
112
  }
113
113
  },
114
+ embedding_model: {
115
+ type: 'string',
116
+ description: 'Embedding model identifier. When null, the worker falls back to runtime config.'
117
+ },
118
+ embedding_provider: {
119
+ type: 'string',
120
+ description: 'Embedding provider name. When null, the worker falls back to runtime config.'
121
+ },
114
122
  search_score_weight: {
115
123
  type: 'number',
116
124
  default: 1
@@ -53,6 +53,18 @@ exports.SearchVector = {
53
53
  },
54
54
  description: 'Column names that feed the embedding. Used by stale trigger to detect content changes.'
55
55
  },
56
+ // ── Model config (optional — flows into job payload) ──────────
57
+ embedding_model: {
58
+ type: 'string',
59
+ description: 'Embedding model identifier (e.g. "nomic-embed-text", "text-embedding-3-small"). ' +
60
+ 'Included in the job payload so the worker knows which model to use. ' +
61
+ 'When null, the worker falls back to runtime config (llm_module / env vars).'
62
+ },
63
+ embedding_provider: {
64
+ type: 'string',
65
+ description: 'Embedding provider name (e.g. "ollama", "openai"). ' +
66
+ 'When null, the worker falls back to runtime config.'
67
+ },
56
68
  enqueue_job: {
57
69
  type: 'boolean',
58
70
  description: 'Auto-create trigger that enqueues embedding generation jobs',
@@ -810,7 +810,9 @@ export interface BlueprintBucketSeed {
810
810
  }
811
811
  /** Storage configuration for an entity type. Seeds initial buckets, overrides module-level settings (expiry times, file size limits, CORS), and provides per-table provisioning overrides via provisions. */
812
812
  export interface BlueprintStorageConfig {
813
- /** Initial bucket seed entries. Each creates a row in {prefix}_buckets during provisioning. Only used for app-level storage (not entity-scoped). */
813
+ /** Discriminator for multi-module storage. Defaults to "default" (omitted from table names). Non-default keys appear as an infix: {prefix}_{storage_key}_buckets. Max 16 chars, lowercase snake_case. */
814
+ storage_key?: string;
815
+ /** Initial bucket seed entries. Each creates a row in {prefix}_buckets during provisioning. */
814
816
  buckets?: BlueprintBucketSeed[];
815
817
  /** Override for presigned upload URL expiry time in seconds. */
816
818
  upload_url_expiry_seconds?: number;
@@ -830,6 +832,41 @@ export interface BlueprintStorageConfig {
830
832
  buckets?: BlueprintEntityTableProvision;
831
833
  };
832
834
  }
835
+ /** A requirement entry within a blueprint achievement. Defines what events must occur to earn the achievement. */
836
+ export interface BlueprintAchievementRequirement {
837
+ /** Name identifier matching an event_type or step name. */
838
+ event_name: string;
839
+ /** Number of events needed to satisfy this requirement. */
840
+ count: number;
841
+ /** Human-readable description of what this requirement entails. */
842
+ description?: string;
843
+ }
844
+ /** A reward entry within a blueprint achievement. Defines credits granted when the achievement is earned. */
845
+ export interface BlueprintAchievementReward {
846
+ /** Type of reward: limit_credit (grants limit credits) or meter_credit (grants meter credits). */
847
+ reward_type: 'limit_credit' | 'meter_credit';
848
+ /** Target limit name or meter slug for the credit grant. */
849
+ target_name: string;
850
+ /** Number of credits to grant. */
851
+ amount: number;
852
+ /** Credit type: permanent, expiring, etc. Defaults to "permanent". */
853
+ credit_type?: string;
854
+ }
855
+ /** An achievement entry for the blueprint achievements[] section. Creates a level with requirements and optional rewards in the events_module. Requires events_module to be provisioned (e.g., via entity_types[].has_levels = true or modules includes events_module). */
856
+ export interface BlueprintAchievement {
857
+ /** Unique name for the achievement level. */
858
+ name: string;
859
+ /** Human-readable description of this achievement. */
860
+ description?: string;
861
+ /** Display ordering priority; lower values appear first. Defaults to 100. */
862
+ priority?: number;
863
+ /** Requirements that must be met to earn this achievement. */
864
+ requirements: BlueprintAchievementRequirement[];
865
+ /** Rewards granted when the achievement is earned. */
866
+ rewards?: BlueprintAchievementReward[];
867
+ /** Entity prefix to scope this achievement to (e.g., "org", "app"). Used to resolve the correct events_module. Defaults to "app". */
868
+ entity_prefix?: string;
869
+ }
833
870
  /** Override object for the entity table created by a BlueprintEntityType. Shape mirrors BlueprintTable / secure_table_provision vocabulary. When supplied, policies[] replaces the default entity-table policies entirely. */
834
871
  export interface BlueprintEntityTableProvision {
835
872
  /** Whether to enable RLS on the entity table. Forwarded to secure_table_provision. Defaults to true. */
@@ -866,16 +903,16 @@ export interface BlueprintEntityType {
866
903
  has_profiles?: boolean;
867
904
  /** Whether to provision a levels module for this entity type. Defaults to false. */
868
905
  has_levels?: boolean;
869
- /** Whether to provision a storage module (buckets, files tables) for this entity type. Defaults to false. */
870
- has_storage?: boolean;
871
906
  /** Whether to provision entity-scoped invite tables ({prefix}_invites, {prefix}_claimed_invites) and a submit_{prefix}_invite_code() function. Defaults to false. */
872
907
  has_invites?: boolean;
908
+ /** Whether to auto-attach an EventTracker to the claimed_invites table for invite-based achievements. Requires has_invites=true AND has_levels=true. When true, records 'invite_claimed' events credited to the sender (inviter) on each claimed invite. Defaults to false. */
909
+ has_invite_achievements?: boolean;
873
910
  /** Escape hatch: when true AND table_provision is NULL, zero policies are provisioned on the entity table. Defaults to false. */
874
911
  skip_entity_policies?: boolean;
875
912
  /** Override for the entity table. Shape mirrors BlueprintTable / secure_table_provision vocabulary. When supplied, its policies[] replaces the five default entity-table policies; is_visible becomes a no-op. When NULL (default), the five default policies are applied (gated by is_visible). */
876
913
  table_provision?: BlueprintEntityTableProvision;
877
- /** Storage configuration. Only used when has_storage is true. Controls RLS policies on storage tables, seeds initial buckets, and overrides module-level settings (expiry times, file size limits, CORS). */
878
- storage?: BlueprintStorageConfig;
914
+ /** Storage configuration (array-only). A non-empty array enables storage provisioning. Each entry creates a separate storage module with its own tables ({prefix}_{storage_key}_buckets/files). Controls RLS policies, bucket seeding, and module-level settings. */
915
+ storage?: BlueprintStorageConfig[];
879
916
  }
880
917
  /** String shorthand -- just the node type name. */
881
918
  export type BlueprintNodeShorthand = 'AuthzAllowAll' | 'AuthzAppMembership' | 'AuthzComposite' | 'AuthzDenyAll' | 'AuthzFilePath' | 'AuthzDirectOwner' | 'AuthzDirectOwnerAny' | 'AuthzEntityMembership' | 'AuthzMemberList' | 'AuthzNotReadOnly' | 'AuthzOrgHierarchy' | 'AuthzPeerOwnership' | 'AuthzPublishable' | 'AuthzRelatedEntityMembership' | 'AuthzRelatedMemberList' | 'AuthzRelatedPeerOwnership' | 'AuthzTemporal' | 'CheckGreaterThan' | 'CheckLessThan' | 'CheckNotEqual' | 'CheckOneOf' | 'LimitAggregate' | 'BillingMeter' | 'DataBulk' | 'ProcessChunks' | 'DataCompositeField' | 'DataDirectOwner' | 'DataEntityMembership' | 'ProcessFileEmbedding' | 'LimitFeatureFlag' | 'DataForceCurrentUser' | 'DataId' | 'ProcessImageEmbedding' | 'DataImmutableFields' | 'DataInflection' | 'DataInheritFromParent' | 'JobTrigger' | 'LimitCounter' | 'DataJsonb' | 'DataOwnedFields' | 'ProcessExtraction' | 'ProcessImageVersions' | 'DataOwnershipInEntity' | 'DataPeoplestamps' | 'DataPublishable' | 'DataRealtime' | 'DataSlug' | 'DataSoftDelete' | 'DataStatusField' | 'DataTags' | 'DataTimestamps' | 'SearchBm25' | 'SearchFullText' | 'SearchSpatial' | 'SearchSpatialAggregate' | 'SearchTrgm' | 'SearchUnified' | 'SearchVector' | 'TableOrganizationSettings' | 'TableUserProfiles' | 'TableUserSettings';
@@ -1140,6 +1177,8 @@ export interface BlueprintDefinition {
1140
1177
  unique_constraints?: BlueprintUniqueConstraint[];
1141
1178
  /** Entity types to provision in Phase 0 (before tables). Each entry creates an entity table with membership modules and security. */
1142
1179
  entity_types?: BlueprintEntityType[];
1143
- /** App-level storage configuration. Creates a storage_module (membership_type = NULL), seeds initial buckets, and overrides module-level settings (expiry times, file size limits, CORS). Use provisions for per-table policy overrides. For entity-scoped storage, use entity_types[].has_storage + entity_types[].storage instead. */
1144
- storage?: BlueprintStorageConfig;
1180
+ /** App-level storage configuration (array-only). Creates storage_module(s) (membership_type = NULL), seeds initial buckets, and overrides module-level settings. Each entry creates a separate storage module. For entity-scoped storage, use entity_types[].storage instead. */
1181
+ storage?: BlueprintStorageConfig[];
1182
+ /** Achievement definitions. Each entry creates a level with requirements and optional rewards in the events_module. Requires events_module to be provisioned (e.g., via entity_types[].has_levels = true or modules includes events_module). */
1183
+ achievements?: BlueprintAchievement[];
1145
1184
  }