@stackframe/stack-shared 2.8.40 → 2.8.43

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 (82) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/apps/apps-config.d.mts +109 -0
  3. package/dist/apps/apps-config.d.ts +109 -0
  4. package/dist/apps/apps-config.js +137 -0
  5. package/dist/apps/apps-config.js.map +1 -0
  6. package/dist/config/format.js +3 -1
  7. package/dist/config/format.js.map +1 -1
  8. package/dist/config/schema-fuzzer.test.d.mts +2 -0
  9. package/dist/config/schema-fuzzer.test.d.ts +2 -0
  10. package/dist/config/schema-fuzzer.test.js +206 -0
  11. package/dist/config/schema-fuzzer.test.js.map +1 -0
  12. package/dist/config/schema.d.mts +302 -182
  13. package/dist/config/schema.d.ts +302 -182
  14. package/dist/config/schema.js +92 -44
  15. package/dist/config/schema.js.map +1 -1
  16. package/dist/esm/apps/apps-config.js +112 -0
  17. package/dist/esm/apps/apps-config.js.map +1 -0
  18. package/dist/esm/config/format.js +3 -1
  19. package/dist/esm/config/format.js.map +1 -1
  20. package/dist/esm/config/schema-fuzzer.test.js +204 -0
  21. package/dist/esm/config/schema-fuzzer.test.js.map +1 -0
  22. package/dist/esm/config/schema.js +94 -46
  23. package/dist/esm/config/schema.js.map +1 -1
  24. package/dist/esm/interface/admin-interface.js +0 -27
  25. package/dist/esm/interface/admin-interface.js.map +1 -1
  26. package/dist/esm/interface/client-interface.js +36 -4
  27. package/dist/esm/interface/client-interface.js.map +1 -1
  28. package/dist/esm/interface/crud/products.js +19 -0
  29. package/dist/esm/interface/crud/products.js.map +1 -0
  30. package/dist/esm/interface/crud/transactions.js +3 -3
  31. package/dist/esm/interface/crud/transactions.js.map +1 -1
  32. package/dist/esm/interface/server-interface.js +22 -0
  33. package/dist/esm/interface/server-interface.js.map +1 -1
  34. package/dist/esm/known-errors.js +30 -16
  35. package/dist/esm/known-errors.js.map +1 -1
  36. package/dist/esm/schema-fields.js +15 -14
  37. package/dist/esm/schema-fields.js.map +1 -1
  38. package/dist/esm/sessions.js +17 -5
  39. package/dist/esm/sessions.js.map +1 -1
  40. package/dist/esm/utils/objects.js +4 -0
  41. package/dist/esm/utils/objects.js.map +1 -1
  42. package/dist/esm/utils/strings.js +5 -1
  43. package/dist/esm/utils/strings.js.map +1 -1
  44. package/dist/index.d.mts +1 -0
  45. package/dist/index.d.ts +1 -0
  46. package/dist/interface/admin-interface.d.mts +1 -6
  47. package/dist/interface/admin-interface.d.ts +1 -6
  48. package/dist/interface/admin-interface.js +0 -27
  49. package/dist/interface/admin-interface.js.map +1 -1
  50. package/dist/interface/client-interface.d.mts +5 -2
  51. package/dist/interface/client-interface.d.ts +5 -2
  52. package/dist/interface/client-interface.js +36 -4
  53. package/dist/interface/client-interface.js.map +1 -1
  54. package/dist/interface/crud/products.d.mts +91 -0
  55. package/dist/interface/crud/products.d.ts +91 -0
  56. package/dist/interface/crud/products.js +45 -0
  57. package/dist/interface/crud/products.js.map +1 -0
  58. package/dist/interface/crud/transactions.d.mts +2 -2
  59. package/dist/interface/crud/transactions.d.ts +2 -2
  60. package/dist/interface/crud/transactions.js +2 -2
  61. package/dist/interface/crud/transactions.js.map +1 -1
  62. package/dist/interface/server-interface.d.mts +10 -2
  63. package/dist/interface/server-interface.d.ts +10 -2
  64. package/dist/interface/server-interface.js +22 -0
  65. package/dist/interface/server-interface.js.map +1 -1
  66. package/dist/known-errors.d.mts +7 -4
  67. package/dist/known-errors.d.ts +7 -4
  68. package/dist/known-errors.js +30 -16
  69. package/dist/known-errors.js.map +1 -1
  70. package/dist/schema-fields.d.mts +8 -6
  71. package/dist/schema-fields.d.ts +8 -6
  72. package/dist/schema-fields.js +18 -17
  73. package/dist/schema-fields.js.map +1 -1
  74. package/dist/sessions.d.mts +2 -1
  75. package/dist/sessions.d.ts +2 -1
  76. package/dist/sessions.js +16 -4
  77. package/dist/sessions.js.map +1 -1
  78. package/dist/utils/objects.js +4 -0
  79. package/dist/utils/objects.js.map +1 -1
  80. package/dist/utils/strings.js +5 -1
  81. package/dist/utils/strings.js.map +1 -1
  82. package/package.json +7 -7
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @stackframe/stack-shared
2
2
 
3
+ ## 2.8.43
4
+
5
+ ## 2.8.42
6
+
7
+ ### Patch Changes
8
+
9
+ - Various changes
10
+
11
+ ## 2.8.41
12
+
13
+ ### Patch Changes
14
+
15
+ - Various changes
16
+
3
17
  ## 2.8.40
4
18
 
5
19
  ### Patch Changes
@@ -0,0 +1,109 @@
1
+ declare const ALL_APPS: {
2
+ readonly authentication: {
3
+ readonly type: "app";
4
+ readonly displayName: "Authentication";
5
+ readonly subtitle: "User sign-in and account management";
6
+ readonly tags: ["auth", "security"];
7
+ readonly stage: "stable";
8
+ };
9
+ readonly teams: {
10
+ readonly type: "app";
11
+ readonly displayName: "Teams";
12
+ readonly subtitle: "Team collaboration and management";
13
+ readonly tags: ["collaboration", "organization"];
14
+ readonly stage: "stable";
15
+ };
16
+ readonly rbac: {
17
+ readonly type: "app";
18
+ readonly displayName: "RBAC";
19
+ readonly subtitle: "Role-based access control and permissions";
20
+ readonly tags: ["security", "permissions"];
21
+ readonly stage: "stable";
22
+ };
23
+ readonly "api-keys": {
24
+ readonly type: "app";
25
+ readonly displayName: "API Keys";
26
+ readonly subtitle: "API key generation and management";
27
+ readonly tags: ["api", "security"];
28
+ readonly stage: "stable";
29
+ };
30
+ readonly payments: {
31
+ readonly type: "app";
32
+ readonly displayName: "Payments";
33
+ readonly subtitle: "Payment processing and subscription management";
34
+ readonly tags: ["billing", "monetization"];
35
+ readonly stage: "stable";
36
+ };
37
+ readonly emails: {
38
+ readonly type: "app";
39
+ readonly displayName: "Emails";
40
+ readonly subtitle: "Email template configuration and management";
41
+ readonly tags: ["communication", "templates"];
42
+ readonly stage: "stable";
43
+ };
44
+ readonly "email-api": {
45
+ readonly type: "app";
46
+ readonly displayName: "Email API";
47
+ readonly subtitle: "Programmatic email sending and delivery";
48
+ readonly tags: ["api", "communication"];
49
+ readonly stage: "alpha";
50
+ };
51
+ readonly "data-vault": {
52
+ readonly type: "app";
53
+ readonly displayName: "Data Vault";
54
+ readonly subtitle: "Secure storage for sensitive user data";
55
+ readonly tags: ["security", "storage"];
56
+ readonly stage: "stable";
57
+ };
58
+ readonly workflows: {
59
+ readonly type: "app";
60
+ readonly displayName: "Workflows";
61
+ readonly subtitle: "Automated business process orchestration";
62
+ readonly tags: ["automation", "processes"];
63
+ readonly stage: "beta";
64
+ };
65
+ readonly webhooks: {
66
+ readonly type: "app";
67
+ readonly displayName: "Webhooks";
68
+ readonly subtitle: "Real-time event notifications and integrations";
69
+ readonly tags: ["integration", "events"];
70
+ readonly stage: "stable";
71
+ };
72
+ readonly "tv-mode": {
73
+ readonly type: "app";
74
+ readonly displayName: "TV mode";
75
+ readonly subtitle: "Dashboard display for large screens";
76
+ readonly tags: ["display", "monitoring"];
77
+ readonly stage: "alpha";
78
+ };
79
+ readonly "launch-checklist": {
80
+ readonly type: "app";
81
+ readonly displayName: "Launch Checklist";
82
+ readonly subtitle: "Pre-launch verification and readiness checks";
83
+ readonly tags: ["deployment", "verification"];
84
+ readonly stage: "alpha";
85
+ };
86
+ readonly catalyst: {
87
+ readonly type: "app";
88
+ readonly displayName: "Catalyst";
89
+ readonly subtitle: "Project scaffolding and rapid development";
90
+ readonly tags: ["development", "tooling"];
91
+ readonly stage: "alpha";
92
+ };
93
+ readonly neon: {
94
+ readonly type: "integration";
95
+ readonly displayName: "Neon";
96
+ readonly subtitle: "Serverless Postgres database integration";
97
+ readonly tags: ["database", "integration"];
98
+ readonly stage: "alpha";
99
+ };
100
+ readonly convex: {
101
+ readonly type: "integration";
102
+ readonly displayName: "Convex";
103
+ readonly subtitle: "Real-time backend platform integration";
104
+ readonly tags: ["database", "integration", "realtime"];
105
+ readonly stage: "alpha";
106
+ };
107
+ };
108
+
109
+ export { ALL_APPS };
@@ -0,0 +1,109 @@
1
+ declare const ALL_APPS: {
2
+ readonly authentication: {
3
+ readonly type: "app";
4
+ readonly displayName: "Authentication";
5
+ readonly subtitle: "User sign-in and account management";
6
+ readonly tags: ["auth", "security"];
7
+ readonly stage: "stable";
8
+ };
9
+ readonly teams: {
10
+ readonly type: "app";
11
+ readonly displayName: "Teams";
12
+ readonly subtitle: "Team collaboration and management";
13
+ readonly tags: ["collaboration", "organization"];
14
+ readonly stage: "stable";
15
+ };
16
+ readonly rbac: {
17
+ readonly type: "app";
18
+ readonly displayName: "RBAC";
19
+ readonly subtitle: "Role-based access control and permissions";
20
+ readonly tags: ["security", "permissions"];
21
+ readonly stage: "stable";
22
+ };
23
+ readonly "api-keys": {
24
+ readonly type: "app";
25
+ readonly displayName: "API Keys";
26
+ readonly subtitle: "API key generation and management";
27
+ readonly tags: ["api", "security"];
28
+ readonly stage: "stable";
29
+ };
30
+ readonly payments: {
31
+ readonly type: "app";
32
+ readonly displayName: "Payments";
33
+ readonly subtitle: "Payment processing and subscription management";
34
+ readonly tags: ["billing", "monetization"];
35
+ readonly stage: "stable";
36
+ };
37
+ readonly emails: {
38
+ readonly type: "app";
39
+ readonly displayName: "Emails";
40
+ readonly subtitle: "Email template configuration and management";
41
+ readonly tags: ["communication", "templates"];
42
+ readonly stage: "stable";
43
+ };
44
+ readonly "email-api": {
45
+ readonly type: "app";
46
+ readonly displayName: "Email API";
47
+ readonly subtitle: "Programmatic email sending and delivery";
48
+ readonly tags: ["api", "communication"];
49
+ readonly stage: "alpha";
50
+ };
51
+ readonly "data-vault": {
52
+ readonly type: "app";
53
+ readonly displayName: "Data Vault";
54
+ readonly subtitle: "Secure storage for sensitive user data";
55
+ readonly tags: ["security", "storage"];
56
+ readonly stage: "stable";
57
+ };
58
+ readonly workflows: {
59
+ readonly type: "app";
60
+ readonly displayName: "Workflows";
61
+ readonly subtitle: "Automated business process orchestration";
62
+ readonly tags: ["automation", "processes"];
63
+ readonly stage: "beta";
64
+ };
65
+ readonly webhooks: {
66
+ readonly type: "app";
67
+ readonly displayName: "Webhooks";
68
+ readonly subtitle: "Real-time event notifications and integrations";
69
+ readonly tags: ["integration", "events"];
70
+ readonly stage: "stable";
71
+ };
72
+ readonly "tv-mode": {
73
+ readonly type: "app";
74
+ readonly displayName: "TV mode";
75
+ readonly subtitle: "Dashboard display for large screens";
76
+ readonly tags: ["display", "monitoring"];
77
+ readonly stage: "alpha";
78
+ };
79
+ readonly "launch-checklist": {
80
+ readonly type: "app";
81
+ readonly displayName: "Launch Checklist";
82
+ readonly subtitle: "Pre-launch verification and readiness checks";
83
+ readonly tags: ["deployment", "verification"];
84
+ readonly stage: "alpha";
85
+ };
86
+ readonly catalyst: {
87
+ readonly type: "app";
88
+ readonly displayName: "Catalyst";
89
+ readonly subtitle: "Project scaffolding and rapid development";
90
+ readonly tags: ["development", "tooling"];
91
+ readonly stage: "alpha";
92
+ };
93
+ readonly neon: {
94
+ readonly type: "integration";
95
+ readonly displayName: "Neon";
96
+ readonly subtitle: "Serverless Postgres database integration";
97
+ readonly tags: ["database", "integration"];
98
+ readonly stage: "alpha";
99
+ };
100
+ readonly convex: {
101
+ readonly type: "integration";
102
+ readonly displayName: "Convex";
103
+ readonly subtitle: "Real-time backend platform integration";
104
+ readonly tags: ["database", "integration", "realtime"];
105
+ readonly stage: "alpha";
106
+ };
107
+ };
108
+
109
+ export { ALL_APPS };
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/apps/apps-config.ts
21
+ var apps_config_exports = {};
22
+ __export(apps_config_exports, {
23
+ ALL_APPS: () => ALL_APPS
24
+ });
25
+ module.exports = __toCommonJS(apps_config_exports);
26
+ var ALL_APPS = {
27
+ "authentication": {
28
+ type: "app",
29
+ displayName: "Authentication",
30
+ subtitle: "User sign-in and account management",
31
+ tags: ["auth", "security"],
32
+ stage: "stable"
33
+ },
34
+ "teams": {
35
+ type: "app",
36
+ displayName: "Teams",
37
+ subtitle: "Team collaboration and management",
38
+ tags: ["collaboration", "organization"],
39
+ stage: "stable"
40
+ },
41
+ "rbac": {
42
+ type: "app",
43
+ displayName: "RBAC",
44
+ subtitle: "Role-based access control and permissions",
45
+ tags: ["security", "permissions"],
46
+ stage: "stable"
47
+ },
48
+ "api-keys": {
49
+ type: "app",
50
+ displayName: "API Keys",
51
+ subtitle: "API key generation and management",
52
+ tags: ["api", "security"],
53
+ stage: "stable"
54
+ },
55
+ "payments": {
56
+ type: "app",
57
+ displayName: "Payments",
58
+ subtitle: "Payment processing and subscription management",
59
+ tags: ["billing", "monetization"],
60
+ stage: "stable"
61
+ },
62
+ "emails": {
63
+ type: "app",
64
+ displayName: "Emails",
65
+ subtitle: "Email template configuration and management",
66
+ tags: ["communication", "templates"],
67
+ stage: "stable"
68
+ },
69
+ "email-api": {
70
+ type: "app",
71
+ displayName: "Email API",
72
+ subtitle: "Programmatic email sending and delivery",
73
+ tags: ["api", "communication"],
74
+ stage: "alpha"
75
+ },
76
+ "data-vault": {
77
+ type: "app",
78
+ displayName: "Data Vault",
79
+ subtitle: "Secure storage for sensitive user data",
80
+ tags: ["security", "storage"],
81
+ stage: "stable"
82
+ },
83
+ "workflows": {
84
+ type: "app",
85
+ displayName: "Workflows",
86
+ subtitle: "Automated business process orchestration",
87
+ tags: ["automation", "processes"],
88
+ stage: "beta"
89
+ },
90
+ "webhooks": {
91
+ type: "app",
92
+ displayName: "Webhooks",
93
+ subtitle: "Real-time event notifications and integrations",
94
+ tags: ["integration", "events"],
95
+ stage: "stable"
96
+ },
97
+ "tv-mode": {
98
+ type: "app",
99
+ displayName: "TV mode",
100
+ subtitle: "Dashboard display for large screens",
101
+ tags: ["display", "monitoring"],
102
+ stage: "alpha"
103
+ },
104
+ "launch-checklist": {
105
+ type: "app",
106
+ displayName: "Launch Checklist",
107
+ subtitle: "Pre-launch verification and readiness checks",
108
+ tags: ["deployment", "verification"],
109
+ stage: "alpha"
110
+ },
111
+ "catalyst": {
112
+ type: "app",
113
+ displayName: "Catalyst",
114
+ subtitle: "Project scaffolding and rapid development",
115
+ tags: ["development", "tooling"],
116
+ stage: "alpha"
117
+ },
118
+ "neon": {
119
+ type: "integration",
120
+ displayName: "Neon",
121
+ subtitle: "Serverless Postgres database integration",
122
+ tags: ["database", "integration"],
123
+ stage: "alpha"
124
+ },
125
+ "convex": {
126
+ type: "integration",
127
+ displayName: "Convex",
128
+ subtitle: "Real-time backend platform integration",
129
+ tags: ["database", "integration", "realtime"],
130
+ stage: "alpha"
131
+ }
132
+ };
133
+ // Annotate the CommonJS export names for ESM import in node:
134
+ 0 && (module.exports = {
135
+ ALL_APPS
136
+ });
137
+ //# sourceMappingURL=apps-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/apps/apps-config.ts"],"sourcesContent":["type App = {\n type: \"app\" | \"integration\",\n displayName: string,\n subtitle: string,\n tags: string[],\n stage: \"alpha\" | \"beta\" | \"stable\",\n};\n\nexport const ALL_APPS = {\n \"authentication\": {\n type: \"app\",\n displayName: \"Authentication\",\n subtitle: \"User sign-in and account management\",\n tags: [\"auth\", \"security\"],\n stage: \"stable\",\n },\n \"teams\": {\n type: \"app\",\n displayName: \"Teams\",\n subtitle: \"Team collaboration and management\",\n tags: [\"collaboration\", \"organization\"],\n stage: \"stable\",\n },\n \"rbac\": {\n type: \"app\",\n displayName: \"RBAC\",\n subtitle: \"Role-based access control and permissions\",\n tags: [\"security\", \"permissions\"],\n stage: \"stable\",\n },\n \"api-keys\": {\n type: \"app\",\n displayName: \"API Keys\",\n subtitle: \"API key generation and management\",\n tags: [\"api\", \"security\"],\n stage: \"stable\",\n },\n \"payments\": {\n type: \"app\",\n displayName: \"Payments\",\n subtitle: \"Payment processing and subscription management\",\n tags: [\"billing\", \"monetization\"],\n stage: \"stable\",\n },\n \"emails\": {\n type: \"app\",\n displayName: \"Emails\",\n subtitle: \"Email template configuration and management\",\n tags: [\"communication\", \"templates\"],\n stage: \"stable\",\n },\n \"email-api\": {\n type: \"app\",\n displayName: \"Email API\",\n subtitle: \"Programmatic email sending and delivery\",\n tags: [\"api\", \"communication\"],\n stage: \"alpha\",\n },\n \"data-vault\": {\n type: \"app\",\n displayName: \"Data Vault\",\n subtitle: \"Secure storage for sensitive user data\",\n tags: [\"security\", \"storage\"],\n stage: \"stable\",\n },\n \"workflows\": {\n type: \"app\",\n displayName: \"Workflows\",\n subtitle: \"Automated business process orchestration\",\n tags: [\"automation\", \"processes\"],\n stage: \"beta\",\n },\n \"webhooks\": {\n type: \"app\",\n displayName: \"Webhooks\",\n subtitle: \"Real-time event notifications and integrations\",\n tags: [\"integration\", \"events\"],\n stage: \"stable\",\n },\n \"tv-mode\": {\n type: \"app\",\n displayName: \"TV mode\",\n subtitle: \"Dashboard display for large screens\",\n tags: [\"display\", \"monitoring\"],\n stage: \"alpha\",\n },\n \"launch-checklist\": {\n type: \"app\",\n displayName: \"Launch Checklist\",\n subtitle: \"Pre-launch verification and readiness checks\",\n tags: [\"deployment\", \"verification\"],\n stage: \"alpha\",\n },\n \"catalyst\": {\n type: \"app\",\n displayName: \"Catalyst\",\n subtitle: \"Project scaffolding and rapid development\",\n tags: [\"development\", \"tooling\"],\n stage: \"alpha\",\n },\n \"neon\": {\n type: \"integration\",\n displayName: \"Neon\",\n subtitle: \"Serverless Postgres database integration\",\n tags: [\"database\", \"integration\"],\n stage: \"alpha\",\n },\n \"convex\": {\n type: \"integration\",\n displayName: \"Convex\",\n subtitle: \"Real-time backend platform integration\",\n tags: [\"database\", \"integration\", \"realtime\"],\n stage: \"alpha\",\n },\n} as const satisfies Record<string, App>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAQO,IAAM,WAAW;AAAA,EACtB,kBAAkB;AAAA,IAChB,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,MAAM,CAAC,QAAQ,UAAU;AAAA,IACzB,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,MAAM,CAAC,iBAAiB,cAAc;AAAA,IACtC,OAAO;AAAA,EACT;AAAA,EACA,QAAQ;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,MAAM,CAAC,YAAY,aAAa;AAAA,IAChC,OAAO;AAAA,EACT;AAAA,EACA,YAAY;AAAA,IACV,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,MAAM,CAAC,OAAO,UAAU;AAAA,IACxB,OAAO;AAAA,EACT;AAAA,EACA,YAAY;AAAA,IACV,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,MAAM,CAAC,WAAW,cAAc;AAAA,IAChC,OAAO;AAAA,EACT;AAAA,EACA,UAAU;AAAA,IACR,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,MAAM,CAAC,iBAAiB,WAAW;AAAA,IACnC,OAAO;AAAA,EACT;AAAA,EACA,aAAa;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,MAAM,CAAC,OAAO,eAAe;AAAA,IAC7B,OAAO;AAAA,EACT;AAAA,EACA,cAAc;AAAA,IACZ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,MAAM,CAAC,YAAY,SAAS;AAAA,IAC5B,OAAO;AAAA,EACT;AAAA,EACA,aAAa;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,MAAM,CAAC,cAAc,WAAW;AAAA,IAChC,OAAO;AAAA,EACT;AAAA,EACA,YAAY;AAAA,IACV,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,MAAM,CAAC,eAAe,QAAQ;AAAA,IAC9B,OAAO;AAAA,EACT;AAAA,EACA,WAAW;AAAA,IACT,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,MAAM,CAAC,WAAW,YAAY;AAAA,IAC9B,OAAO;AAAA,EACT;AAAA,EACA,oBAAoB;AAAA,IAClB,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,MAAM,CAAC,cAAc,cAAc;AAAA,IACnC,OAAO;AAAA,EACT;AAAA,EACA,YAAY;AAAA,IACV,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,MAAM,CAAC,eAAe,SAAS;AAAA,IAC/B,OAAO;AAAA,EACT;AAAA,EACA,QAAQ;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,MAAM,CAAC,YAAY,aAAa;AAAA,IAChC,OAAO;AAAA,EACT;AAAA,EACA,UAAU;AAAA,IACR,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,MAAM,CAAC,YAAY,eAAe,UAAU;AAAA,IAC5C,OAAO;AAAA,EACT;AACF;","names":[]}
@@ -61,7 +61,9 @@ function getInvalidConfigValueReason(value, options = {}) {
61
61
  break;
62
62
  } else if (Array.isArray(value)) {
63
63
  for (const [index, v] of value.entries()) {
64
- const reason = getInvalidConfigValueReason(v, { valueName: `${valueName}[${index}]` });
64
+ const elementValueName = `${valueName}[${index}]`;
65
+ if (v === null) return `${elementValueName} is null; tuple elements cannot be null`;
66
+ const reason = getInvalidConfigValueReason(v, { valueName: elementValueName });
65
67
  if (reason) return reason;
66
68
  }
67
69
  } else {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/config/format.ts"],"sourcesContent":["// see https://github.com/stack-auth/info/blob/main/eng-handbook/random-thoughts/config-json-format.md\n\nimport { StackAssertionError, throwErr } from \"../utils/errors\";\nimport { deleteKey, filterUndefined, get, hasAndNotUndefined, set } from \"../utils/objects\";\nimport { OptionalKeys, RequiredKeys } from \"../utils/types\";\n\n\nexport type ConfigValue = string | number | boolean | null | ConfigValue[] | Config;\nexport type Config = {\n [keyOrDotNotation: string]: ConfigValue | undefined, // must support undefined for optional values\n};\n\nexport type NormalizedConfigValue = string | number | boolean | NormalizedConfig | NormalizedConfigValue[];\nexport type NormalizedConfig = {\n [key: string]: NormalizedConfigValue | undefined, // must support undefined for optional values\n};\n\nexport type _NormalizesTo<N> = N extends object ? (\n & Config\n & { [K in OptionalKeys<N>]?: _NormalizesTo<N[K]> | null }\n & { [K in RequiredKeys<N>]: undefined extends N[K] ? _NormalizesTo<N[K]> | null : _NormalizesTo<N[K]> }\n & { [K in `${string}.${string}`]: ConfigValue }\n) : N;\nexport type NormalizesTo<N extends NormalizedConfig> = _NormalizesTo<N>;\n\n/**\n * Note that a config can both be valid and not normalizable.\n */\nexport function isValidConfig(c: unknown): c is Config {\n return getInvalidConfigReason(c) === undefined;\n}\n\nexport function getInvalidConfigReason(c: unknown, options: { configName?: string } = {}): string | undefined {\n const configName = options.configName ?? 'config';\n if (c === null || typeof c !== 'object') return `${configName} must be a non-null object`;\n for (const [key, value] of Object.entries(c)) {\n if (value === undefined) continue;\n if (typeof key !== 'string') return `${configName} must have only string keys (found: ${typeof key})`;\n if (!key.match(/^[a-zA-Z0-9_:$][a-zA-Z_:$0-9\\-]*(?:\\.[a-zA-Z0-9_:$][a-zA-Z_:$0-9\\-]*)*$/)) return `All keys of ${configName} must consist of only alphanumeric characters, dots, underscores, colons, dollar signs, or hyphens and start with a character other than a hyphen (found: ${key})`;\n\n const entryName = `${configName}.${key}`;\n const reason = getInvalidConfigValueReason(value, { valueName: entryName });\n if (reason) return reason;\n }\n return undefined;\n}\n\nfunction getInvalidConfigValueReason(value: unknown, options: { valueName?: string } = {}): string | undefined {\n const valueName = options.valueName ?? 'value';\n switch (typeof value) {\n case 'string':\n case 'number':\n case 'boolean': {\n break;\n }\n case 'object': {\n if (value === null) {\n break;\n } else if (Array.isArray(value)) {\n for (const [index, v] of value.entries()) {\n const reason = getInvalidConfigValueReason(v, { valueName: `${valueName}[${index}]` });\n if (reason) return reason;\n }\n } else {\n const reason = getInvalidConfigReason(value, { configName: valueName });\n if (reason) return reason;\n }\n break;\n }\n default: {\n return `${valueName} has an invalid value type ${typeof value} (value: ${value})`;\n }\n }\n return undefined;\n}\n\nexport function assertValidConfig(c: unknown) {\n const reason = getInvalidConfigReason(c);\n if (reason) throw new StackAssertionError(`Invalid config: ${reason}`, { c });\n}\n\nexport function override(c1: Config, ...configs: Config[]) {\n if (configs.length === 0) return c1;\n if (configs.length > 1) return override(override(c1, configs[0]), ...configs.slice(1));\n const c2 = configs[0];\n\n assertValidConfig(c1);\n assertValidConfig(c2);\n\n let result = c1;\n for (const key of Object.keys(filterUndefined(c2))) {\n result = Object.fromEntries(\n Object.entries(result).filter(([k]) => k !== key && !k.startsWith(key + '.'))\n );\n }\n\n return {\n ...result,\n ...filterUndefined(c2),\n };\n}\n\nundefined?.test(\"override(...)\", ({ expect }) => {\n expect(\n override(\n {\n a: 1,\n b: 2,\n \"c.d\": 3,\n \"c.e.f\": 4,\n \"c.g\": 5,\n h: [6, { i: 7 }, 8],\n k: 123,\n l: undefined,\n },\n {\n a: 9,\n \"c.d\": 10,\n \"c.e\": null,\n \"h.0\": 11,\n \"h.1\": {\n j: 12,\n },\n k: undefined,\n },\n )\n ).toEqual({\n a: 9,\n b: 2,\n \"c.d\": 10,\n \"c.e\": null,\n \"c.g\": 5,\n h: [6, { i: 7 }, 8],\n \"h.0\": 11,\n \"h.1\": {\n j: 12,\n },\n k: 123,\n l: undefined,\n });\n});\n\ntype NormalizeOptions = {\n /**\n * What to do if a dot notation is used on a value that is not an object.\n *\n * - \"throw\" (default): Throw an error.\n * - \"ignore\": Ignore the dot notation field.\n */\n onDotIntoNonObject?: \"throw\" | \"ignore\",\n /**\n * What to do if a dot notation is used on a value that is null.\n *\n * - \"like-non-object\" (default): Treat it like a non-object. See `onDotIntoNonObject`.\n * - \"throw\": Throw an error.\n * - \"ignore\": Ignore the dot notation field.\n * - \"empty-object\": Set the value to an empty object.\n */\n onDotIntoNull?: \"like-non-object\" | \"throw\" | \"ignore\" | \"empty-object\",\n}\n\nexport class NormalizationError extends Error {\n constructor(...args: ConstructorParameters<typeof Error>) {\n super(...args);\n }\n}\nNormalizationError.prototype.name = \"NormalizationError\";\n\nexport function isNormalized(c: Config): c is NormalizedConfig {\n assertValidConfig(c);\n for (const [key, value] of Object.entries(c)) {\n if (value === undefined) continue;\n if (key.includes('.')) return false;\n if (value === null) return false;\n }\n return true;\n}\n\nexport function assertNormalized(c: Config): asserts c is NormalizedConfig {\n assertValidConfig(c);\n if (!isNormalized(c)) throw new StackAssertionError(`Config is not normalized: ${JSON.stringify(c)}`);\n}\n\nexport function normalize(c: Config, options: NormalizeOptions = {}): NormalizedConfig {\n assertValidConfig(c);\n const onDotIntoNonObject = options.onDotIntoNonObject ?? \"throw\";\n const onDotIntoNull = options.onDotIntoNull ?? \"like-non-object\";\n\n const countDots = (s: string) => s.match(/\\./g)?.length ?? 0;\n const result: NormalizedConfig = {};\n const keysByDepth = Object.keys(c).sort((a, b) => countDots(a) - countDots(b));\n\n outer: for (const key of keysByDepth) {\n const keySegmentsWithoutLast = key.split('.');\n const last = keySegmentsWithoutLast.pop() ?? throwErr('split returns empty array?');\n const value = get(c, key);\n if (value === undefined) continue;\n\n let current: NormalizedConfig = result;\n for (const keySegment of keySegmentsWithoutLast) {\n if (!hasAndNotUndefined(current, keySegment)) {\n switch (onDotIntoNull === \"like-non-object\" ? onDotIntoNonObject : onDotIntoNull) {\n case \"throw\": {\n throw new NormalizationError(`Tried to use dot notation to access ${JSON.stringify(key)}, but ${JSON.stringify(keySegment)} doesn't exist on the object (or is null).`);\n }\n case \"ignore\": {\n continue outer;\n }\n case \"empty-object\": {\n set(current, keySegment, {});\n break;\n }\n }\n }\n const value = get(current, keySegment);\n if (typeof value !== 'object') {\n switch (onDotIntoNonObject) {\n case \"throw\": {\n throw new NormalizationError(`Tried to use dot notation to access ${JSON.stringify(key)}, but ${JSON.stringify(keySegment)} is not an object.`);\n }\n case \"ignore\": {\n continue outer;\n }\n }\n }\n current = value as NormalizedConfig;\n }\n setNormalizedValue(current, last, value, options);\n }\n return result;\n}\n\nfunction normalizeValue(value: ConfigValue, options: NormalizeOptions): NormalizedConfigValue {\n if (value === null) throw new NormalizationError(\"Tried to normalize a null value\");\n if (Array.isArray(value)) return value.map(v => normalizeValue(v, options));\n if (typeof value === 'object') return normalize(value, options);\n return value;\n}\n\nfunction setNormalizedValue(result: NormalizedConfig, key: string, value: ConfigValue, options: NormalizeOptions) {\n if (value === null) {\n if (hasAndNotUndefined(result, key)) {\n deleteKey(result, key);\n }\n } else {\n set(result, key, normalizeValue(value, options));\n }\n}\n\nundefined?.test(\"normalize(...)\", ({ expect }) => {\n expect(normalize({\n a: 9,\n b: 2,\n c: {},\n \"c.d\": 10,\n \"c.e\": null,\n \"c.g\": 5,\n h: [6, { i: 7 }, 8],\n \"h.0\": 11,\n \"h.1\": {\n j: 12,\n },\n k: { l: {} },\n \"k.l.m\": 13,\n n: undefined,\n }, { onDotIntoNonObject: \"ignore\" })).toEqual({\n a: 9,\n b: 2,\n c: {\n d: 10,\n g: 5,\n },\n h: [11, { j: 12 }, 8],\n k: { l: { m: 13 } },\n });\n\n // dotting into null\n expect(() => normalize({\n \"b.c\": 2,\n }, { onDotIntoNonObject: \"throw\" })).toThrow(`Tried to use dot notation to access \"b.c\", but \"b\" doesn't exist on the object (or is null)`);\n expect(() => normalize({\n b: null,\n \"b.c\": 2,\n }, { onDotIntoNonObject: \"throw\" })).toThrow(`Tried to use dot notation to access \"b.c\", but \"b\" doesn't exist on the object (or is null)`);\n expect(normalize({\n \"b.c\": 2,\n }, { onDotIntoNonObject: \"ignore\" })).toEqual({});\n\n // dotting into non-object\n expect(() => normalize({\n b: 1,\n \"b.c\": 2,\n }, { onDotIntoNonObject: \"throw\" })).toThrow(`Tried to use dot notation to access \"b.c\", but \"b\" is not an object`);\n expect(normalize({\n b: 1,\n \"b.c\": 2,\n }, { onDotIntoNonObject: \"ignore\" })).toEqual({ b: 1 });\n});\n"],"mappings":"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","names":["value"]}
1
+ {"version":3,"sources":["../../src/config/format.ts"],"sourcesContent":["// see https://github.com/stack-auth/info/blob/main/eng-handbook/random-thoughts/config-json-format.md\n\nimport { StackAssertionError, throwErr } from \"../utils/errors\";\nimport { deleteKey, filterUndefined, get, hasAndNotUndefined, set } from \"../utils/objects\";\nimport { OptionalKeys, RequiredKeys } from \"../utils/types\";\n\n\nexport type ConfigValue = string | number | boolean | null | ConfigValue[] | Config;\nexport type Config = {\n [keyOrDotNotation: string]: ConfigValue | undefined, // must support undefined for optional values\n};\n\nexport type NormalizedConfigValue = string | number | boolean | NormalizedConfig | NormalizedConfigValue[];\nexport type NormalizedConfig = {\n [key: string]: NormalizedConfigValue | undefined, // must support undefined for optional values\n};\n\nexport type _NormalizesTo<N> = N extends object ? (\n & Config\n & { [K in OptionalKeys<N>]?: _NormalizesTo<N[K]> | null }\n & { [K in RequiredKeys<N>]: undefined extends N[K] ? _NormalizesTo<N[K]> | null : _NormalizesTo<N[K]> }\n & { [K in `${string}.${string}`]: ConfigValue }\n) : N;\nexport type NormalizesTo<N extends NormalizedConfig> = _NormalizesTo<N>;\n\n/**\n * Note that a config can both be valid and not normalizable.\n */\nexport function isValidConfig(c: unknown): c is Config {\n return getInvalidConfigReason(c) === undefined;\n}\n\nexport function getInvalidConfigReason(c: unknown, options: { configName?: string } = {}): string | undefined {\n const configName = options.configName ?? 'config';\n if (c === null || typeof c !== 'object') return `${configName} must be a non-null object`;\n for (const [key, value] of Object.entries(c)) {\n if (value === undefined) continue;\n if (typeof key !== 'string') return `${configName} must have only string keys (found: ${typeof key})`;\n if (!key.match(/^[a-zA-Z0-9_:$][a-zA-Z_:$0-9\\-]*(?:\\.[a-zA-Z0-9_:$][a-zA-Z_:$0-9\\-]*)*$/)) return `All keys of ${configName} must consist of only alphanumeric characters, dots, underscores, colons, dollar signs, or hyphens and start with a character other than a hyphen (found: ${key})`;\n\n const entryName = `${configName}.${key}`;\n const reason = getInvalidConfigValueReason(value, { valueName: entryName });\n if (reason) return reason;\n }\n return undefined;\n}\n\nfunction getInvalidConfigValueReason(value: unknown, options: { valueName?: string } = {}): string | undefined {\n const valueName = options.valueName ?? 'value';\n switch (typeof value) {\n case 'string':\n case 'number':\n case 'boolean': {\n break;\n }\n case 'object': {\n if (value === null) {\n break;\n } else if (Array.isArray(value)) {\n for (const [index, v] of value.entries()) {\n const elementValueName = `${valueName}[${index}]`;\n if (v === null) return `${elementValueName} is null; tuple elements cannot be null`;\n const reason = getInvalidConfigValueReason(v, { valueName: elementValueName });\n if (reason) return reason;\n }\n } else {\n const reason = getInvalidConfigReason(value, { configName: valueName });\n if (reason) return reason;\n }\n break;\n }\n default: {\n return `${valueName} has an invalid value type ${typeof value} (value: ${value})`;\n }\n }\n return undefined;\n}\n\nexport function assertValidConfig(c: unknown) {\n const reason = getInvalidConfigReason(c);\n if (reason) throw new StackAssertionError(`Invalid config: ${reason}`, { c });\n}\n\nexport function override(c1: Config, ...configs: Config[]) {\n if (configs.length === 0) return c1;\n if (configs.length > 1) return override(override(c1, configs[0]), ...configs.slice(1));\n const c2 = configs[0];\n\n assertValidConfig(c1);\n assertValidConfig(c2);\n\n let result = c1;\n for (const key of Object.keys(filterUndefined(c2))) {\n result = Object.fromEntries(\n Object.entries(result).filter(([k]) => k !== key && !k.startsWith(key + '.'))\n );\n }\n\n return {\n ...result,\n ...filterUndefined(c2),\n };\n}\n\nundefined?.test(\"override(...)\", ({ expect }) => {\n expect(\n override(\n {\n a: 1,\n b: 2,\n \"c.d\": 3,\n \"c.e.f\": 4,\n \"c.g\": 5,\n h: [6, { i: 7 }, 8],\n k: 123,\n l: undefined,\n },\n {\n a: 9,\n \"c.d\": 10,\n \"c.e\": null,\n \"h.0\": 11,\n \"h.1\": {\n j: 12,\n },\n k: undefined,\n },\n )\n ).toEqual({\n a: 9,\n b: 2,\n \"c.d\": 10,\n \"c.e\": null,\n \"c.g\": 5,\n h: [6, { i: 7 }, 8],\n \"h.0\": 11,\n \"h.1\": {\n j: 12,\n },\n k: 123,\n l: undefined,\n });\n});\n\ntype NormalizeOptions = {\n /**\n * What to do if a dot notation is used on a value that is not an object.\n *\n * - \"throw\" (default): Throw an error.\n * - \"ignore\": Ignore the dot notation field.\n */\n onDotIntoNonObject?: \"throw\" | \"ignore\",\n /**\n * What to do if a dot notation is used on a value that is null.\n *\n * - \"like-non-object\" (default): Treat it like a non-object. See `onDotIntoNonObject`.\n * - \"throw\": Throw an error.\n * - \"ignore\": Ignore the dot notation field.\n * - \"empty-object\": Set the value to an empty object.\n */\n onDotIntoNull?: \"like-non-object\" | \"throw\" | \"ignore\" | \"empty-object\",\n}\n\nexport class NormalizationError extends Error {\n constructor(...args: ConstructorParameters<typeof Error>) {\n super(...args);\n }\n}\nNormalizationError.prototype.name = \"NormalizationError\";\n\nexport function isNormalized(c: Config): c is NormalizedConfig {\n assertValidConfig(c);\n for (const [key, value] of Object.entries(c)) {\n if (value === undefined) continue;\n if (key.includes('.')) return false;\n if (value === null) return false;\n }\n return true;\n}\n\nexport function assertNormalized(c: Config): asserts c is NormalizedConfig {\n assertValidConfig(c);\n if (!isNormalized(c)) throw new StackAssertionError(`Config is not normalized: ${JSON.stringify(c)}`);\n}\n\nexport function normalize(c: Config, options: NormalizeOptions = {}): NormalizedConfig {\n assertValidConfig(c);\n const onDotIntoNonObject = options.onDotIntoNonObject ?? \"throw\";\n const onDotIntoNull = options.onDotIntoNull ?? \"like-non-object\";\n\n const countDots = (s: string) => s.match(/\\./g)?.length ?? 0;\n const result: NormalizedConfig = {};\n const keysByDepth = Object.keys(c).sort((a, b) => countDots(a) - countDots(b));\n\n outer: for (const key of keysByDepth) {\n const keySegmentsWithoutLast = key.split('.');\n const last = keySegmentsWithoutLast.pop() ?? throwErr('split returns empty array?');\n const value = get(c, key);\n if (value === undefined) continue;\n\n let current: NormalizedConfig = result;\n for (const keySegment of keySegmentsWithoutLast) {\n if (!hasAndNotUndefined(current, keySegment)) {\n switch (onDotIntoNull === \"like-non-object\" ? onDotIntoNonObject : onDotIntoNull) {\n case \"throw\": {\n throw new NormalizationError(`Tried to use dot notation to access ${JSON.stringify(key)}, but ${JSON.stringify(keySegment)} doesn't exist on the object (or is null).`);\n }\n case \"ignore\": {\n continue outer;\n }\n case \"empty-object\": {\n set(current, keySegment, {});\n break;\n }\n }\n }\n const value = get(current, keySegment);\n if (typeof value !== 'object') {\n switch (onDotIntoNonObject) {\n case \"throw\": {\n throw new NormalizationError(`Tried to use dot notation to access ${JSON.stringify(key)}, but ${JSON.stringify(keySegment)} is not an object.`);\n }\n case \"ignore\": {\n continue outer;\n }\n }\n }\n current = value as NormalizedConfig;\n }\n setNormalizedValue(current, last, value, options);\n }\n return result;\n}\n\nfunction normalizeValue(value: ConfigValue, options: NormalizeOptions): NormalizedConfigValue {\n if (value === null) throw new NormalizationError(\"Tried to normalize a null value\");\n if (Array.isArray(value)) return value.map(v => normalizeValue(v, options));\n if (typeof value === 'object') return normalize(value, options);\n return value;\n}\n\nfunction setNormalizedValue(result: NormalizedConfig, key: string, value: ConfigValue, options: NormalizeOptions) {\n if (value === null) {\n if (hasAndNotUndefined(result, key)) {\n deleteKey(result, key);\n }\n } else {\n set(result, key, normalizeValue(value, options));\n }\n}\n\nundefined?.test(\"normalize(...)\", ({ expect }) => {\n expect(normalize({\n a: 9,\n b: 2,\n c: {},\n \"c.d\": 10,\n \"c.e\": null,\n \"c.g\": 5,\n h: [6, { i: 7 }, 8],\n \"h.0\": 11,\n \"h.1\": {\n j: 12,\n },\n k: { l: {} },\n \"k.l.m\": 13,\n n: undefined,\n }, { onDotIntoNonObject: \"ignore\" })).toEqual({\n a: 9,\n b: 2,\n c: {\n d: 10,\n g: 5,\n },\n h: [11, { j: 12 }, 8],\n k: { l: { m: 13 } },\n });\n\n // dotting into null\n expect(() => normalize({\n \"b.c\": 2,\n }, { onDotIntoNonObject: \"throw\" })).toThrow(`Tried to use dot notation to access \"b.c\", but \"b\" doesn't exist on the object (or is null)`);\n expect(() => normalize({\n b: null,\n \"b.c\": 2,\n }, { onDotIntoNonObject: \"throw\" })).toThrow(`Tried to use dot notation to access \"b.c\", but \"b\" doesn't exist on the object (or is null)`);\n expect(normalize({\n \"b.c\": 2,\n }, { onDotIntoNonObject: \"ignore\" })).toEqual({});\n\n // dotting into non-object\n expect(() => normalize({\n b: 1,\n \"b.c\": 2,\n }, { onDotIntoNonObject: \"throw\" })).toThrow(`Tried to use dot notation to access \"b.c\", but \"b\" is not an object`);\n expect(normalize({\n b: 1,\n \"b.c\": 2,\n }, { onDotIntoNonObject: \"ignore\" })).toEqual({ b: 1 });\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,oBAA8C;AAC9C,qBAAyE;AAyBlE,SAAS,cAAc,GAAyB;AACrD,SAAO,uBAAuB,CAAC,MAAM;AACvC;AAEO,SAAS,uBAAuB,GAAY,UAAmC,CAAC,GAAuB;AAC5G,QAAM,aAAa,QAAQ,cAAc;AACzC,MAAI,MAAM,QAAQ,OAAO,MAAM,SAAU,QAAO,GAAG,UAAU;AAC7D,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,CAAC,GAAG;AAC5C,QAAI,UAAU,OAAW;AACzB,QAAI,OAAO,QAAQ,SAAU,QAAO,GAAG,UAAU,uCAAuC,OAAO,GAAG;AAClG,QAAI,CAAC,IAAI,MAAM,yEAAyE,EAAG,QAAO,eAAe,UAAU,6JAA6J,GAAG;AAE3R,UAAM,YAAY,GAAG,UAAU,IAAI,GAAG;AACtC,UAAM,SAAS,4BAA4B,OAAO,EAAE,WAAW,UAAU,CAAC;AAC1E,QAAI,OAAQ,QAAO;AAAA,EACrB;AACA,SAAO;AACT;AAEA,SAAS,4BAA4B,OAAgB,UAAkC,CAAC,GAAuB;AAC7G,QAAM,YAAY,QAAQ,aAAa;AACvC,UAAQ,OAAO,OAAO;AAAA,IACpB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK,WAAW;AACd;AAAA,IACF;AAAA,IACA,KAAK,UAAU;AACb,UAAI,UAAU,MAAM;AAClB;AAAA,MACF,WAAW,MAAM,QAAQ,KAAK,GAAG;AAC/B,mBAAW,CAAC,OAAO,CAAC,KAAK,MAAM,QAAQ,GAAG;AACxC,gBAAM,mBAAmB,GAAG,SAAS,IAAI,KAAK;AAC9C,cAAI,MAAM,KAAM,QAAO,GAAG,gBAAgB;AAC1C,gBAAM,SAAS,4BAA4B,GAAG,EAAE,WAAW,iBAAiB,CAAC;AAC7E,cAAI,OAAQ,QAAO;AAAA,QACrB;AAAA,MACF,OAAO;AACL,cAAM,SAAS,uBAAuB,OAAO,EAAE,YAAY,UAAU,CAAC;AACtE,YAAI,OAAQ,QAAO;AAAA,MACrB;AACA;AAAA,IACF;AAAA,IACA,SAAS;AACP,aAAO,GAAG,SAAS,8BAA8B,OAAO,KAAK,YAAY,KAAK;AAAA,IAChF;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,kBAAkB,GAAY;AAC5C,QAAM,SAAS,uBAAuB,CAAC;AACvC,MAAI,OAAQ,OAAM,IAAI,kCAAoB,mBAAmB,MAAM,IAAI,EAAE,EAAE,CAAC;AAC9E;AAEO,SAAS,SAAS,OAAe,SAAmB;AACzD,MAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,MAAI,QAAQ,SAAS,EAAG,QAAO,SAAS,SAAS,IAAI,QAAQ,CAAC,CAAC,GAAG,GAAG,QAAQ,MAAM,CAAC,CAAC;AACrF,QAAM,KAAK,QAAQ,CAAC;AAEpB,oBAAkB,EAAE;AACpB,oBAAkB,EAAE;AAEpB,MAAI,SAAS;AACb,aAAW,OAAO,OAAO,SAAK,gCAAgB,EAAE,CAAC,GAAG;AAClD,aAAS,OAAO;AAAA,MACd,OAAO,QAAQ,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,MAAM,OAAO,CAAC,EAAE,WAAW,MAAM,GAAG,CAAC;AAAA,IAC9E;AAAA,EACF;AAEA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,OAAG,gCAAgB,EAAE;AAAA,EACvB;AACF;AA6DO,IAAM,qBAAN,cAAiC,MAAM;AAAA,EAC5C,eAAe,MAA2C;AACxD,UAAM,GAAG,IAAI;AAAA,EACf;AACF;AACA,mBAAmB,UAAU,OAAO;AAE7B,SAAS,aAAa,GAAkC;AAC7D,oBAAkB,CAAC;AACnB,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,CAAC,GAAG;AAC5C,QAAI,UAAU,OAAW;AACzB,QAAI,IAAI,SAAS,GAAG,EAAG,QAAO;AAC9B,QAAI,UAAU,KAAM,QAAO;AAAA,EAC7B;AACA,SAAO;AACT;AAEO,SAAS,iBAAiB,GAA0C;AACzE,oBAAkB,CAAC;AACnB,MAAI,CAAC,aAAa,CAAC,EAAG,OAAM,IAAI,kCAAoB,6BAA6B,KAAK,UAAU,CAAC,CAAC,EAAE;AACtG;AAEO,SAAS,UAAU,GAAW,UAA4B,CAAC,GAAqB;AACrF,oBAAkB,CAAC;AACnB,QAAM,qBAAqB,QAAQ,sBAAsB;AACzD,QAAM,gBAAgB,QAAQ,iBAAiB;AAE/C,QAAM,YAAY,CAAC,MAAc,EAAE,MAAM,KAAK,GAAG,UAAU;AAC3D,QAAM,SAA2B,CAAC;AAClC,QAAM,cAAc,OAAO,KAAK,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,UAAU,CAAC,IAAI,UAAU,CAAC,CAAC;AAE7E,QAAO,YAAW,OAAO,aAAa;AACpC,UAAM,yBAAyB,IAAI,MAAM,GAAG;AAC5C,UAAM,OAAO,uBAAuB,IAAI,SAAK,wBAAS,4BAA4B;AAClF,UAAM,YAAQ,oBAAI,GAAG,GAAG;AACxB,QAAI,UAAU,OAAW;AAEzB,QAAI,UAA4B;AAChC,eAAW,cAAc,wBAAwB;AAC/C,UAAI,KAAC,mCAAmB,SAAS,UAAU,GAAG;AAC5C,gBAAQ,kBAAkB,oBAAoB,qBAAqB,eAAe;AAAA,UAChF,KAAK,SAAS;AACZ,kBAAM,IAAI,mBAAmB,uCAAuC,KAAK,UAAU,GAAG,CAAC,SAAS,KAAK,UAAU,UAAU,CAAC,4CAA4C;AAAA,UACxK;AAAA,UACA,KAAK,UAAU;AACb,qBAAS;AAAA,UACX;AAAA,UACA,KAAK,gBAAgB;AACnB,oCAAI,SAAS,YAAY,CAAC,CAAC;AAC3B;AAAA,UACF;AAAA,QACF;AAAA,MACF;AACA,YAAMA,aAAQ,oBAAI,SAAS,UAAU;AACrC,UAAI,OAAOA,WAAU,UAAU;AAC7B,gBAAQ,oBAAoB;AAAA,UAC1B,KAAK,SAAS;AACZ,kBAAM,IAAI,mBAAmB,uCAAuC,KAAK,UAAU,GAAG,CAAC,SAAS,KAAK,UAAU,UAAU,CAAC,oBAAoB;AAAA,UAChJ;AAAA,UACA,KAAK,UAAU;AACb,qBAAS;AAAA,UACX;AAAA,QACF;AAAA,MACF;AACA,gBAAUA;AAAA,IACZ;AACA,uBAAmB,SAAS,MAAM,OAAO,OAAO;AAAA,EAClD;AACA,SAAO;AACT;AAEA,SAAS,eAAe,OAAoB,SAAkD;AAC5F,MAAI,UAAU,KAAM,OAAM,IAAI,mBAAmB,iCAAiC;AAClF,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,IAAI,OAAK,eAAe,GAAG,OAAO,CAAC;AAC1E,MAAI,OAAO,UAAU,SAAU,QAAO,UAAU,OAAO,OAAO;AAC9D,SAAO;AACT;AAEA,SAAS,mBAAmB,QAA0B,KAAa,OAAoB,SAA2B;AAChH,MAAI,UAAU,MAAM;AAClB,YAAI,mCAAmB,QAAQ,GAAG,GAAG;AACnC,oCAAU,QAAQ,GAAG;AAAA,IACvB;AAAA,EACF,OAAO;AACL,4BAAI,QAAQ,KAAK,eAAe,OAAO,OAAO,CAAC;AAAA,EACjD;AACF;","names":["value"]}
@@ -0,0 +1,2 @@
1
+
2
+ export { }
@@ -0,0 +1,2 @@
1
+
2
+ export { }