priceos 0.0.41 → 0.0.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.
package/dist/cli.cjs CHANGED
@@ -111,6 +111,7 @@ ${text}`);
111
111
  }
112
112
  const features = await res.json();
113
113
  const typeByKey = /* @__PURE__ */ new Map();
114
+ const trackingByKey = /* @__PURE__ */ new Map();
114
115
  for (const feature of features ?? []) {
115
116
  if (!feature?.featureKey) continue;
116
117
  const key = feature.featureKey;
@@ -118,10 +119,18 @@ ${text}`);
118
119
  const currentType = typeByKey.get(key);
119
120
  if (!currentType) {
120
121
  typeByKey.set(key, nextType);
122
+ } else if (currentType !== nextType) {
123
+ typeByKey.set(key, "unknown");
124
+ }
125
+ if (nextType !== "limit") continue;
126
+ const nextTracking = feature.tracksUsage === true ? "tracked" : feature.tracksUsage === false ? "untracked" : "unknown";
127
+ const currentTracking = trackingByKey.get(key);
128
+ if (!currentTracking) {
129
+ trackingByKey.set(key, nextTracking);
121
130
  continue;
122
131
  }
123
- if (currentType !== nextType) {
124
- typeByKey.set(key, "unknown");
132
+ if (currentTracking !== nextTracking) {
133
+ trackingByKey.set(key, "unknown");
125
134
  }
126
135
  }
127
136
  const keys = [...typeByKey.keys()].sort();
@@ -130,7 +139,7 @@ ${text}`);
130
139
  const limitUnion = limitKeys.length ? limitKeys.map((k) => JSON.stringify(k)).join(" | ") : "never";
131
140
  const mapLines = keys.map((key) => {
132
141
  const featureType = typeByKey.get(key);
133
- const accessType = featureType === "boolean" ? "BooleanFeatureAccess" : featureType === "limit" ? "LimitFeatureAccess" : "FeatureAccessEntry";
142
+ const accessType = featureType === "boolean" ? "BooleanFeatureAccess" : featureType === "limit" ? trackingByKey.get(key) === "tracked" ? "TrackedLimitFeatureAccess" : trackingByKey.get(key) === "untracked" ? "UntrackedLimitFeatureAccess" : "LimitFeatureAccess" : "FeatureAccessEntry";
134
143
  return ` ${JSON.stringify(key)}: ${accessType};`;
135
144
  });
136
145
  const content = `// Auto-generated by PriceOS (priceos generate-types). Do not edit.
@@ -140,18 +149,34 @@ export type BooleanFeatureAccess = {
140
149
  type: "boolean";
141
150
  hasAccess: boolean;
142
151
  };
143
- export type LimitFeatureAccess = {
152
+ export type LimitFeatureUsage = {
153
+ used: number;
154
+ remaining: number | null;
155
+ bonusRemaining: number;
156
+ bonusUsed: number;
157
+ resetsWhen: "billing_period" | "calendar";
158
+ resetType: "never" | "day" | "week" | "month" | "year";
159
+ nextReset: number | null;
160
+ lastReset: number | null;
161
+ };
162
+ export type TrackedLimitFeatureAccess = {
144
163
  type: "limit";
145
164
  hasAccess: boolean;
146
165
  isUnlimited: boolean;
147
166
  limit: number | null;
148
- used: number;
167
+ usage: LimitFeatureUsage;
149
168
  };
169
+ export type UntrackedLimitFeatureAccess = {
170
+ type: "limit";
171
+ hasAccess: boolean;
172
+ isUnlimited: boolean;
173
+ limit: number | null;
174
+ };
175
+ export type LimitFeatureAccess = TrackedLimitFeatureAccess | UntrackedLimitFeatureAccess;
150
176
  export type FeatureAccessEntry = BooleanFeatureAccess | LimitFeatureAccess;
151
177
  export type FeatureAccessMap = {
152
- __limitFeatureKey?: LimitFeatureKey;
153
178
  ${mapLines.join("\n")}
154
- } & Record<string, FeatureAccessEntry>;
179
+ };
155
180
  `;
156
181
  await import_promises.default.mkdir(import_node_path.default.dirname(outPath), { recursive: true });
157
182
  await import_promises.default.writeFile(outPath, content, "utf8");
package/dist/cli.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\n\ntype Feature = { featureKey: string; type?: \"boolean\" | \"limit\" | null };\n\nfunction argValue(args: string[], name: string) {\n const idx = args.indexOf(name);\n if (idx === -1) return undefined;\n return args[idx + 1];\n}\n\nfunction hasFlag(args: string[], name: string) {\n return args.includes(name);\n}\n\nasync function readEnvFile(filePath: string) {\n try {\n const raw = await fs.readFile(filePath, \"utf8\");\n const entries: Record<string, string> = {};\n for (const line of raw.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith(\"#\")) continue;\n const eqIdx = trimmed.indexOf(\"=\");\n if (eqIdx === -1) continue;\n const rawKey = trimmed.slice(0, eqIdx).trim();\n const key = rawKey.startsWith(\"export \") ? rawKey.slice(\"export \".length).trim() : rawKey;\n let value = trimmed.slice(eqIdx + 1).trim();\n if (\n (value.startsWith(\"\\\"\") && value.endsWith(\"\\\"\")) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n if (key) {\n entries[key] = value;\n }\n }\n return entries;\n } catch {\n return {};\n }\n}\n\nfunction printHelp() {\n console.log(`\npriceos generate-types\n\nGenerates TypeScript feature access types for your PriceOS workspace.\n\nOptions:\n --api-key <key> PriceOS API key (defaults to .env.local, .env, or env PRICEOS_API_KEY) [required]\n --out <path> Output .d.ts file (default: priceos.d.ts in current directory)\n --out-dir <path> Output directory for priceos.d.ts (ignored if --out is set)\n -h, --help Show help\n\nExamples:\n priceos generate-types --api-key sk_test_... --out ./priceos.d.ts\n priceos generate-types --api-key sk_test_... --out-dir ./src\n`.trim());\n}\n\nasync function main() {\n const args = process.argv.slice(2);\n\n if (args.length === 0 || hasFlag(args, \"--help\") || hasFlag(args, \"-h\")) {\n printHelp();\n process.exit(args.length === 0 ? 1 : 0);\n }\n\n const cmd = args[0];\n if (cmd !== \"generate-types\") {\n console.error(`Unknown command: ${cmd}`);\n printHelp();\n process.exit(1);\n }\n\n const envLocal = await readEnvFile(path.resolve(process.cwd(), \".env.local\"));\n const envDefault = await readEnvFile(path.resolve(process.cwd(), \".env\"));\n const apiKey =\n argValue(args, \"--api-key\") ??\n envLocal.PRICEOS_API_KEY ??\n envDefault.PRICEOS_API_KEY ??\n process.env.PRICEOS_API_KEY;\n\n if (!apiKey) {\n console.error(\"Missing API key. Provide --api-key <key> or set PRICEOS_API_KEY in .env.local/.env.\");\n process.exit(1);\n }\n\n const outRel = argValue(args, \"--out\");\n const outDir = argValue(args, \"--out-dir\");\n const outFile = outRel ?? \"priceos.d.ts\";\n const outPath = outDir && !outRel\n ? path.resolve(process.cwd(), outDir, outFile)\n : path.resolve(process.cwd(), outFile);\n const outDisplay = outDir && !outRel ? path.join(outDir, outFile) : outFile;\n\n const url = \"https://api.priceos.com/v1/features\";\n const res = await fetch(url, {\n headers: { \"x-api-key\": apiKey },\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n console.error(`Failed to fetch features: ${res.status} ${res.statusText}\\n${text}`);\n process.exit(1);\n }\n\n const features = (await res.json()) as Feature[];\n const typeByKey = new Map<string, \"boolean\" | \"limit\" | \"unknown\">();\n\n for (const feature of features ?? []) {\n if (!feature?.featureKey) continue;\n const key = feature.featureKey;\n const nextType = feature.type === \"boolean\" || feature.type === \"limit\" ? feature.type : \"unknown\";\n const currentType = typeByKey.get(key);\n if (!currentType) {\n typeByKey.set(key, nextType);\n continue;\n }\n if (currentType !== nextType) {\n typeByKey.set(key, \"unknown\");\n }\n }\n\n const keys = [...typeByKey.keys()].sort();\n const union = keys.length ? keys.map((k) => JSON.stringify(k)).join(\" | \") : \"never\";\n const limitKeys = keys.filter((key) => typeByKey.get(key) === \"limit\");\n const limitUnion = limitKeys.length ? limitKeys.map((k) => JSON.stringify(k)).join(\" | \") : \"never\";\n const mapLines = keys.map((key) => {\n const featureType = typeByKey.get(key);\n const accessType =\n featureType === \"boolean\"\n ? \"BooleanFeatureAccess\"\n : featureType === \"limit\"\n ? \"LimitFeatureAccess\"\n : \"FeatureAccessEntry\";\n return ` ${JSON.stringify(key)}: ${accessType};`;\n });\n\n const content = `// Auto-generated by PriceOS (priceos generate-types). Do not edit.\nexport type FeatureKey = ${union};\nexport type LimitFeatureKey = ${limitUnion};\nexport type BooleanFeatureAccess = {\n type: \"boolean\";\n hasAccess: boolean;\n};\nexport type LimitFeatureAccess = {\n type: \"limit\";\n hasAccess: boolean;\n isUnlimited: boolean;\n limit: number | null;\n used: number;\n};\nexport type FeatureAccessEntry = BooleanFeatureAccess | LimitFeatureAccess;\nexport type FeatureAccessMap = {\n __limitFeatureKey?: LimitFeatureKey;\n${mapLines.join(\"\\n\")}\n} & Record<string, FeatureAccessEntry>;\n`;\n\n await fs.mkdir(path.dirname(outPath), { recursive: true });\n await fs.writeFile(outPath, content, \"utf8\");\n\n console.log(`Generated ${outDisplay} (${keys.length} feature keys)`);\n}\n\nmain().catch((e) => {\n console.error(e);\n process.exit(1);\n});\n"],"mappings":"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","names":["fs","path"]}
1
+ {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\n\ntype Feature = {\n featureKey: string;\n type?: \"boolean\" | \"limit\" | null;\n tracksUsage?: boolean | null;\n};\n\nfunction argValue(args: string[], name: string) {\n const idx = args.indexOf(name);\n if (idx === -1) return undefined;\n return args[idx + 1];\n}\n\nfunction hasFlag(args: string[], name: string) {\n return args.includes(name);\n}\n\nasync function readEnvFile(filePath: string) {\n try {\n const raw = await fs.readFile(filePath, \"utf8\");\n const entries: Record<string, string> = {};\n for (const line of raw.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith(\"#\")) continue;\n const eqIdx = trimmed.indexOf(\"=\");\n if (eqIdx === -1) continue;\n const rawKey = trimmed.slice(0, eqIdx).trim();\n const key = rawKey.startsWith(\"export \") ? rawKey.slice(\"export \".length).trim() : rawKey;\n let value = trimmed.slice(eqIdx + 1).trim();\n if (\n (value.startsWith(\"\\\"\") && value.endsWith(\"\\\"\")) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n if (key) {\n entries[key] = value;\n }\n }\n return entries;\n } catch {\n return {};\n }\n}\n\nfunction printHelp() {\n console.log(`\npriceos generate-types\n\nGenerates TypeScript feature access types for your PriceOS workspace.\n\nOptions:\n --api-key <key> PriceOS API key (defaults to .env.local, .env, or env PRICEOS_API_KEY) [required]\n --out <path> Output .d.ts file (default: priceos.d.ts in current directory)\n --out-dir <path> Output directory for priceos.d.ts (ignored if --out is set)\n -h, --help Show help\n\nExamples:\n priceos generate-types --api-key sk_test_... --out ./priceos.d.ts\n priceos generate-types --api-key sk_test_... --out-dir ./src\n`.trim());\n}\n\nasync function main() {\n const args = process.argv.slice(2);\n\n if (args.length === 0 || hasFlag(args, \"--help\") || hasFlag(args, \"-h\")) {\n printHelp();\n process.exit(args.length === 0 ? 1 : 0);\n }\n\n const cmd = args[0];\n if (cmd !== \"generate-types\") {\n console.error(`Unknown command: ${cmd}`);\n printHelp();\n process.exit(1);\n }\n\n const envLocal = await readEnvFile(path.resolve(process.cwd(), \".env.local\"));\n const envDefault = await readEnvFile(path.resolve(process.cwd(), \".env\"));\n const apiKey =\n argValue(args, \"--api-key\") ??\n envLocal.PRICEOS_API_KEY ??\n envDefault.PRICEOS_API_KEY ??\n process.env.PRICEOS_API_KEY;\n\n if (!apiKey) {\n console.error(\"Missing API key. Provide --api-key <key> or set PRICEOS_API_KEY in .env.local/.env.\");\n process.exit(1);\n }\n\n const outRel = argValue(args, \"--out\");\n const outDir = argValue(args, \"--out-dir\");\n const outFile = outRel ?? \"priceos.d.ts\";\n const outPath = outDir && !outRel\n ? path.resolve(process.cwd(), outDir, outFile)\n : path.resolve(process.cwd(), outFile);\n const outDisplay = outDir && !outRel ? path.join(outDir, outFile) : outFile;\n\n const url = \"https://api.priceos.com/v1/features\";\n const res = await fetch(url, {\n headers: { \"x-api-key\": apiKey },\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n console.error(`Failed to fetch features: ${res.status} ${res.statusText}\\n${text}`);\n process.exit(1);\n }\n\n const features = (await res.json()) as Feature[];\n const typeByKey = new Map<string, \"boolean\" | \"limit\" | \"unknown\">();\n const trackingByKey = new Map<string, \"tracked\" | \"untracked\" | \"unknown\">();\n\n for (const feature of features ?? []) {\n if (!feature?.featureKey) continue;\n const key = feature.featureKey;\n const nextType = feature.type === \"boolean\" || feature.type === \"limit\" ? feature.type : \"unknown\";\n const currentType = typeByKey.get(key);\n if (!currentType) {\n typeByKey.set(key, nextType);\n } else if (currentType !== nextType) {\n typeByKey.set(key, \"unknown\");\n }\n\n if (nextType !== \"limit\") continue;\n\n const nextTracking =\n feature.tracksUsage === true\n ? \"tracked\"\n : feature.tracksUsage === false\n ? \"untracked\"\n : \"unknown\";\n const currentTracking = trackingByKey.get(key);\n if (!currentTracking) {\n trackingByKey.set(key, nextTracking);\n continue;\n }\n if (currentTracking !== nextTracking) {\n trackingByKey.set(key, \"unknown\");\n }\n }\n\n const keys = [...typeByKey.keys()].sort();\n const union = keys.length ? keys.map((k) => JSON.stringify(k)).join(\" | \") : \"never\";\n const limitKeys = keys.filter((key) => typeByKey.get(key) === \"limit\");\n const limitUnion = limitKeys.length ? limitKeys.map((k) => JSON.stringify(k)).join(\" | \") : \"never\";\n const mapLines = keys.map((key) => {\n const featureType = typeByKey.get(key);\n const accessType =\n featureType === \"boolean\"\n ? \"BooleanFeatureAccess\"\n : featureType === \"limit\"\n ? trackingByKey.get(key) === \"tracked\"\n ? \"TrackedLimitFeatureAccess\"\n : trackingByKey.get(key) === \"untracked\"\n ? \"UntrackedLimitFeatureAccess\"\n : \"LimitFeatureAccess\"\n : \"FeatureAccessEntry\";\n return ` ${JSON.stringify(key)}: ${accessType};`;\n });\n\n const content = `// Auto-generated by PriceOS (priceos generate-types). Do not edit.\nexport type FeatureKey = ${union};\nexport type LimitFeatureKey = ${limitUnion};\nexport type BooleanFeatureAccess = {\n type: \"boolean\";\n hasAccess: boolean;\n};\nexport type LimitFeatureUsage = {\n used: number;\n remaining: number | null;\n bonusRemaining: number;\n bonusUsed: number;\n resetsWhen: \"billing_period\" | \"calendar\";\n resetType: \"never\" | \"day\" | \"week\" | \"month\" | \"year\";\n nextReset: number | null;\n lastReset: number | null;\n};\nexport type TrackedLimitFeatureAccess = {\n type: \"limit\";\n hasAccess: boolean;\n isUnlimited: boolean;\n limit: number | null;\n usage: LimitFeatureUsage;\n};\nexport type UntrackedLimitFeatureAccess = {\n type: \"limit\";\n hasAccess: boolean;\n isUnlimited: boolean;\n limit: number | null;\n};\nexport type LimitFeatureAccess = TrackedLimitFeatureAccess | UntrackedLimitFeatureAccess;\nexport type FeatureAccessEntry = BooleanFeatureAccess | LimitFeatureAccess;\nexport type FeatureAccessMap = {\n${mapLines.join(\"\\n\")}\n};\n`;\n\n await fs.mkdir(path.dirname(outPath), { recursive: true });\n await fs.writeFile(outPath, content, \"utf8\");\n\n console.log(`Generated ${outDisplay} (${keys.length} feature keys)`);\n}\n\nmain().catch((e) => {\n console.error(e);\n process.exit(1);\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AACA,sBAAe;AACf,uBAAiB;AAQjB,SAAS,SAAS,MAAgB,MAAc;AAC9C,QAAM,MAAM,KAAK,QAAQ,IAAI;AAC7B,MAAI,QAAQ,GAAI,QAAO;AACvB,SAAO,KAAK,MAAM,CAAC;AACrB;AAEA,SAAS,QAAQ,MAAgB,MAAc;AAC7C,SAAO,KAAK,SAAS,IAAI;AAC3B;AAEA,eAAe,YAAY,UAAkB;AAC3C,MAAI;AACF,UAAM,MAAM,MAAM,gBAAAA,QAAG,SAAS,UAAU,MAAM;AAC9C,UAAM,UAAkC,CAAC;AACzC,eAAW,QAAQ,IAAI,MAAM,OAAO,GAAG;AACrC,YAAM,UAAU,KAAK,KAAK;AAC1B,UAAI,CAAC,WAAW,QAAQ,WAAW,GAAG,EAAG;AACzC,YAAM,QAAQ,QAAQ,QAAQ,GAAG;AACjC,UAAI,UAAU,GAAI;AAClB,YAAM,SAAS,QAAQ,MAAM,GAAG,KAAK,EAAE,KAAK;AAC5C,YAAM,MAAM,OAAO,WAAW,SAAS,IAAI,OAAO,MAAM,UAAU,MAAM,EAAE,KAAK,IAAI;AACnF,UAAI,QAAQ,QAAQ,MAAM,QAAQ,CAAC,EAAE,KAAK;AAC1C,UACG,MAAM,WAAW,GAAI,KAAK,MAAM,SAAS,GAAI,KAC7C,MAAM,WAAW,GAAG,KAAK,MAAM,SAAS,GAAG,GAC5C;AACA,gBAAQ,MAAM,MAAM,GAAG,EAAE;AAAA,MAC3B;AACA,UAAI,KAAK;AACP,gBAAQ,GAAG,IAAI;AAAA,MACjB;AAAA,IACF;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,SAAS,YAAY;AACnB,UAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcZ,KAAK,CAAC;AACR;AAEA,eAAe,OAAO;AACpB,QAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AAEjC,MAAI,KAAK,WAAW,KAAK,QAAQ,MAAM,QAAQ,KAAK,QAAQ,MAAM,IAAI,GAAG;AACvE,cAAU;AACV,YAAQ,KAAK,KAAK,WAAW,IAAI,IAAI,CAAC;AAAA,EACxC;AAEA,QAAM,MAAM,KAAK,CAAC;AAClB,MAAI,QAAQ,kBAAkB;AAC5B,YAAQ,MAAM,oBAAoB,GAAG,EAAE;AACvC,cAAU;AACV,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,WAAW,MAAM,YAAY,iBAAAC,QAAK,QAAQ,QAAQ,IAAI,GAAG,YAAY,CAAC;AAC5E,QAAM,aAAa,MAAM,YAAY,iBAAAA,QAAK,QAAQ,QAAQ,IAAI,GAAG,MAAM,CAAC;AACxE,QAAM,SACJ,SAAS,MAAM,WAAW,KAC1B,SAAS,mBACT,WAAW,mBACX,QAAQ,IAAI;AAEd,MAAI,CAAC,QAAQ;AACX,YAAQ,MAAM,qFAAqF;AACnG,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,SAAS,SAAS,MAAM,OAAO;AACrC,QAAM,SAAS,SAAS,MAAM,WAAW;AACzC,QAAM,UAAU,UAAU;AAC1B,QAAM,UAAU,UAAU,CAAC,SACvB,iBAAAA,QAAK,QAAQ,QAAQ,IAAI,GAAG,QAAQ,OAAO,IAC3C,iBAAAA,QAAK,QAAQ,QAAQ,IAAI,GAAG,OAAO;AACvC,QAAM,aAAa,UAAU,CAAC,SAAS,iBAAAA,QAAK,KAAK,QAAQ,OAAO,IAAI;AAEpE,QAAM,MAAM;AACZ,QAAM,MAAM,MAAM,MAAM,KAAK;AAAA,IAC3B,SAAS,EAAE,aAAa,OAAO;AAAA,EACjC,CAAC;AAED,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,EAAE;AAC5C,YAAQ,MAAM,6BAA6B,IAAI,MAAM,IAAI,IAAI,UAAU;AAAA,EAAK,IAAI,EAAE;AAClF,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,WAAY,MAAM,IAAI,KAAK;AACjC,QAAM,YAAY,oBAAI,IAA6C;AACnE,QAAM,gBAAgB,oBAAI,IAAiD;AAE3E,aAAW,WAAW,YAAY,CAAC,GAAG;AACpC,QAAI,CAAC,SAAS,WAAY;AAC1B,UAAM,MAAM,QAAQ;AACpB,UAAM,WAAW,QAAQ,SAAS,aAAa,QAAQ,SAAS,UAAU,QAAQ,OAAO;AACzF,UAAM,cAAc,UAAU,IAAI,GAAG;AACrC,QAAI,CAAC,aAAa;AAChB,gBAAU,IAAI,KAAK,QAAQ;AAAA,IAC7B,WAAW,gBAAgB,UAAU;AACnC,gBAAU,IAAI,KAAK,SAAS;AAAA,IAC9B;AAEA,QAAI,aAAa,QAAS;AAE1B,UAAM,eACJ,QAAQ,gBAAgB,OACpB,YACA,QAAQ,gBAAgB,QACtB,cACA;AACR,UAAM,kBAAkB,cAAc,IAAI,GAAG;AAC7C,QAAI,CAAC,iBAAiB;AACpB,oBAAc,IAAI,KAAK,YAAY;AACnC;AAAA,IACF;AACA,QAAI,oBAAoB,cAAc;AACpC,oBAAc,IAAI,KAAK,SAAS;AAAA,IAClC;AAAA,EACF;AAEA,QAAM,OAAO,CAAC,GAAG,UAAU,KAAK,CAAC,EAAE,KAAK;AACxC,QAAM,QAAQ,KAAK,SAAS,KAAK,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI;AAC7E,QAAM,YAAY,KAAK,OAAO,CAAC,QAAQ,UAAU,IAAI,GAAG,MAAM,OAAO;AACrE,QAAM,aAAa,UAAU,SAAS,UAAU,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI;AAC5F,QAAM,WAAW,KAAK,IAAI,CAAC,QAAQ;AACjC,UAAM,cAAc,UAAU,IAAI,GAAG;AACrC,UAAM,aACJ,gBAAgB,YACZ,yBACA,gBAAgB,UACd,cAAc,IAAI,GAAG,MAAM,YACzB,8BACA,cAAc,IAAI,GAAG,MAAM,cACzB,gCACA,uBACJ;AACR,WAAO,KAAK,KAAK,UAAU,GAAG,CAAC,KAAK,UAAU;AAAA,EAChD,CAAC;AAED,QAAM,UAAU;AAAA,2BACS,KAAK;AAAA,gCACA,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA+BxC,SAAS,KAAK,IAAI,CAAC;AAAA;AAAA;AAInB,QAAM,gBAAAD,QAAG,MAAM,iBAAAC,QAAK,QAAQ,OAAO,GAAG,EAAE,WAAW,KAAK,CAAC;AACzD,QAAM,gBAAAD,QAAG,UAAU,SAAS,SAAS,MAAM;AAE3C,UAAQ,IAAI,aAAa,UAAU,KAAK,KAAK,MAAM,gBAAgB;AACrE;AAEA,KAAK,EAAE,MAAM,CAAC,MAAM;AAClB,UAAQ,MAAM,CAAC;AACf,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["fs","path"]}
package/dist/cli.js CHANGED
@@ -88,6 +88,7 @@ ${text}`);
88
88
  }
89
89
  const features = await res.json();
90
90
  const typeByKey = /* @__PURE__ */ new Map();
91
+ const trackingByKey = /* @__PURE__ */ new Map();
91
92
  for (const feature of features ?? []) {
92
93
  if (!feature?.featureKey) continue;
93
94
  const key = feature.featureKey;
@@ -95,10 +96,18 @@ ${text}`);
95
96
  const currentType = typeByKey.get(key);
96
97
  if (!currentType) {
97
98
  typeByKey.set(key, nextType);
99
+ } else if (currentType !== nextType) {
100
+ typeByKey.set(key, "unknown");
101
+ }
102
+ if (nextType !== "limit") continue;
103
+ const nextTracking = feature.tracksUsage === true ? "tracked" : feature.tracksUsage === false ? "untracked" : "unknown";
104
+ const currentTracking = trackingByKey.get(key);
105
+ if (!currentTracking) {
106
+ trackingByKey.set(key, nextTracking);
98
107
  continue;
99
108
  }
100
- if (currentType !== nextType) {
101
- typeByKey.set(key, "unknown");
109
+ if (currentTracking !== nextTracking) {
110
+ trackingByKey.set(key, "unknown");
102
111
  }
103
112
  }
104
113
  const keys = [...typeByKey.keys()].sort();
@@ -107,7 +116,7 @@ ${text}`);
107
116
  const limitUnion = limitKeys.length ? limitKeys.map((k) => JSON.stringify(k)).join(" | ") : "never";
108
117
  const mapLines = keys.map((key) => {
109
118
  const featureType = typeByKey.get(key);
110
- const accessType = featureType === "boolean" ? "BooleanFeatureAccess" : featureType === "limit" ? "LimitFeatureAccess" : "FeatureAccessEntry";
119
+ const accessType = featureType === "boolean" ? "BooleanFeatureAccess" : featureType === "limit" ? trackingByKey.get(key) === "tracked" ? "TrackedLimitFeatureAccess" : trackingByKey.get(key) === "untracked" ? "UntrackedLimitFeatureAccess" : "LimitFeatureAccess" : "FeatureAccessEntry";
111
120
  return ` ${JSON.stringify(key)}: ${accessType};`;
112
121
  });
113
122
  const content = `// Auto-generated by PriceOS (priceos generate-types). Do not edit.
@@ -117,18 +126,34 @@ export type BooleanFeatureAccess = {
117
126
  type: "boolean";
118
127
  hasAccess: boolean;
119
128
  };
120
- export type LimitFeatureAccess = {
129
+ export type LimitFeatureUsage = {
130
+ used: number;
131
+ remaining: number | null;
132
+ bonusRemaining: number;
133
+ bonusUsed: number;
134
+ resetsWhen: "billing_period" | "calendar";
135
+ resetType: "never" | "day" | "week" | "month" | "year";
136
+ nextReset: number | null;
137
+ lastReset: number | null;
138
+ };
139
+ export type TrackedLimitFeatureAccess = {
121
140
  type: "limit";
122
141
  hasAccess: boolean;
123
142
  isUnlimited: boolean;
124
143
  limit: number | null;
125
- used: number;
144
+ usage: LimitFeatureUsage;
126
145
  };
146
+ export type UntrackedLimitFeatureAccess = {
147
+ type: "limit";
148
+ hasAccess: boolean;
149
+ isUnlimited: boolean;
150
+ limit: number | null;
151
+ };
152
+ export type LimitFeatureAccess = TrackedLimitFeatureAccess | UntrackedLimitFeatureAccess;
127
153
  export type FeatureAccessEntry = BooleanFeatureAccess | LimitFeatureAccess;
128
154
  export type FeatureAccessMap = {
129
- __limitFeatureKey?: LimitFeatureKey;
130
155
  ${mapLines.join("\n")}
131
- } & Record<string, FeatureAccessEntry>;
156
+ };
132
157
  `;
133
158
  await fs.mkdir(path.dirname(outPath), { recursive: true });
134
159
  await fs.writeFile(outPath, content, "utf8");
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\n\ntype Feature = { featureKey: string; type?: \"boolean\" | \"limit\" | null };\n\nfunction argValue(args: string[], name: string) {\n const idx = args.indexOf(name);\n if (idx === -1) return undefined;\n return args[idx + 1];\n}\n\nfunction hasFlag(args: string[], name: string) {\n return args.includes(name);\n}\n\nasync function readEnvFile(filePath: string) {\n try {\n const raw = await fs.readFile(filePath, \"utf8\");\n const entries: Record<string, string> = {};\n for (const line of raw.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith(\"#\")) continue;\n const eqIdx = trimmed.indexOf(\"=\");\n if (eqIdx === -1) continue;\n const rawKey = trimmed.slice(0, eqIdx).trim();\n const key = rawKey.startsWith(\"export \") ? rawKey.slice(\"export \".length).trim() : rawKey;\n let value = trimmed.slice(eqIdx + 1).trim();\n if (\n (value.startsWith(\"\\\"\") && value.endsWith(\"\\\"\")) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n if (key) {\n entries[key] = value;\n }\n }\n return entries;\n } catch {\n return {};\n }\n}\n\nfunction printHelp() {\n console.log(`\npriceos generate-types\n\nGenerates TypeScript feature access types for your PriceOS workspace.\n\nOptions:\n --api-key <key> PriceOS API key (defaults to .env.local, .env, or env PRICEOS_API_KEY) [required]\n --out <path> Output .d.ts file (default: priceos.d.ts in current directory)\n --out-dir <path> Output directory for priceos.d.ts (ignored if --out is set)\n -h, --help Show help\n\nExamples:\n priceos generate-types --api-key sk_test_... --out ./priceos.d.ts\n priceos generate-types --api-key sk_test_... --out-dir ./src\n`.trim());\n}\n\nasync function main() {\n const args = process.argv.slice(2);\n\n if (args.length === 0 || hasFlag(args, \"--help\") || hasFlag(args, \"-h\")) {\n printHelp();\n process.exit(args.length === 0 ? 1 : 0);\n }\n\n const cmd = args[0];\n if (cmd !== \"generate-types\") {\n console.error(`Unknown command: ${cmd}`);\n printHelp();\n process.exit(1);\n }\n\n const envLocal = await readEnvFile(path.resolve(process.cwd(), \".env.local\"));\n const envDefault = await readEnvFile(path.resolve(process.cwd(), \".env\"));\n const apiKey =\n argValue(args, \"--api-key\") ??\n envLocal.PRICEOS_API_KEY ??\n envDefault.PRICEOS_API_KEY ??\n process.env.PRICEOS_API_KEY;\n\n if (!apiKey) {\n console.error(\"Missing API key. Provide --api-key <key> or set PRICEOS_API_KEY in .env.local/.env.\");\n process.exit(1);\n }\n\n const outRel = argValue(args, \"--out\");\n const outDir = argValue(args, \"--out-dir\");\n const outFile = outRel ?? \"priceos.d.ts\";\n const outPath = outDir && !outRel\n ? path.resolve(process.cwd(), outDir, outFile)\n : path.resolve(process.cwd(), outFile);\n const outDisplay = outDir && !outRel ? path.join(outDir, outFile) : outFile;\n\n const url = \"https://api.priceos.com/v1/features\";\n const res = await fetch(url, {\n headers: { \"x-api-key\": apiKey },\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n console.error(`Failed to fetch features: ${res.status} ${res.statusText}\\n${text}`);\n process.exit(1);\n }\n\n const features = (await res.json()) as Feature[];\n const typeByKey = new Map<string, \"boolean\" | \"limit\" | \"unknown\">();\n\n for (const feature of features ?? []) {\n if (!feature?.featureKey) continue;\n const key = feature.featureKey;\n const nextType = feature.type === \"boolean\" || feature.type === \"limit\" ? feature.type : \"unknown\";\n const currentType = typeByKey.get(key);\n if (!currentType) {\n typeByKey.set(key, nextType);\n continue;\n }\n if (currentType !== nextType) {\n typeByKey.set(key, \"unknown\");\n }\n }\n\n const keys = [...typeByKey.keys()].sort();\n const union = keys.length ? keys.map((k) => JSON.stringify(k)).join(\" | \") : \"never\";\n const limitKeys = keys.filter((key) => typeByKey.get(key) === \"limit\");\n const limitUnion = limitKeys.length ? limitKeys.map((k) => JSON.stringify(k)).join(\" | \") : \"never\";\n const mapLines = keys.map((key) => {\n const featureType = typeByKey.get(key);\n const accessType =\n featureType === \"boolean\"\n ? \"BooleanFeatureAccess\"\n : featureType === \"limit\"\n ? \"LimitFeatureAccess\"\n : \"FeatureAccessEntry\";\n return ` ${JSON.stringify(key)}: ${accessType};`;\n });\n\n const content = `// Auto-generated by PriceOS (priceos generate-types). Do not edit.\nexport type FeatureKey = ${union};\nexport type LimitFeatureKey = ${limitUnion};\nexport type BooleanFeatureAccess = {\n type: \"boolean\";\n hasAccess: boolean;\n};\nexport type LimitFeatureAccess = {\n type: \"limit\";\n hasAccess: boolean;\n isUnlimited: boolean;\n limit: number | null;\n used: number;\n};\nexport type FeatureAccessEntry = BooleanFeatureAccess | LimitFeatureAccess;\nexport type FeatureAccessMap = {\n __limitFeatureKey?: LimitFeatureKey;\n${mapLines.join(\"\\n\")}\n} & Record<string, FeatureAccessEntry>;\n`;\n\n await fs.mkdir(path.dirname(outPath), { recursive: true });\n await fs.writeFile(outPath, content, \"utf8\");\n\n console.log(`Generated ${outDisplay} (${keys.length} feature keys)`);\n}\n\nmain().catch((e) => {\n console.error(e);\n process.exit(1);\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\n\ntype Feature = {\n featureKey: string;\n type?: \"boolean\" | \"limit\" | null;\n tracksUsage?: boolean | null;\n};\n\nfunction argValue(args: string[], name: string) {\n const idx = args.indexOf(name);\n if (idx === -1) return undefined;\n return args[idx + 1];\n}\n\nfunction hasFlag(args: string[], name: string) {\n return args.includes(name);\n}\n\nasync function readEnvFile(filePath: string) {\n try {\n const raw = await fs.readFile(filePath, \"utf8\");\n const entries: Record<string, string> = {};\n for (const line of raw.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith(\"#\")) continue;\n const eqIdx = trimmed.indexOf(\"=\");\n if (eqIdx === -1) continue;\n const rawKey = trimmed.slice(0, eqIdx).trim();\n const key = rawKey.startsWith(\"export \") ? rawKey.slice(\"export \".length).trim() : rawKey;\n let value = trimmed.slice(eqIdx + 1).trim();\n if (\n (value.startsWith(\"\\\"\") && value.endsWith(\"\\\"\")) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n if (key) {\n entries[key] = value;\n }\n }\n return entries;\n } catch {\n return {};\n }\n}\n\nfunction printHelp() {\n console.log(`\npriceos generate-types\n\nGenerates TypeScript feature access types for your PriceOS workspace.\n\nOptions:\n --api-key <key> PriceOS API key (defaults to .env.local, .env, or env PRICEOS_API_KEY) [required]\n --out <path> Output .d.ts file (default: priceos.d.ts in current directory)\n --out-dir <path> Output directory for priceos.d.ts (ignored if --out is set)\n -h, --help Show help\n\nExamples:\n priceos generate-types --api-key sk_test_... --out ./priceos.d.ts\n priceos generate-types --api-key sk_test_... --out-dir ./src\n`.trim());\n}\n\nasync function main() {\n const args = process.argv.slice(2);\n\n if (args.length === 0 || hasFlag(args, \"--help\") || hasFlag(args, \"-h\")) {\n printHelp();\n process.exit(args.length === 0 ? 1 : 0);\n }\n\n const cmd = args[0];\n if (cmd !== \"generate-types\") {\n console.error(`Unknown command: ${cmd}`);\n printHelp();\n process.exit(1);\n }\n\n const envLocal = await readEnvFile(path.resolve(process.cwd(), \".env.local\"));\n const envDefault = await readEnvFile(path.resolve(process.cwd(), \".env\"));\n const apiKey =\n argValue(args, \"--api-key\") ??\n envLocal.PRICEOS_API_KEY ??\n envDefault.PRICEOS_API_KEY ??\n process.env.PRICEOS_API_KEY;\n\n if (!apiKey) {\n console.error(\"Missing API key. Provide --api-key <key> or set PRICEOS_API_KEY in .env.local/.env.\");\n process.exit(1);\n }\n\n const outRel = argValue(args, \"--out\");\n const outDir = argValue(args, \"--out-dir\");\n const outFile = outRel ?? \"priceos.d.ts\";\n const outPath = outDir && !outRel\n ? path.resolve(process.cwd(), outDir, outFile)\n : path.resolve(process.cwd(), outFile);\n const outDisplay = outDir && !outRel ? path.join(outDir, outFile) : outFile;\n\n const url = \"https://api.priceos.com/v1/features\";\n const res = await fetch(url, {\n headers: { \"x-api-key\": apiKey },\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n console.error(`Failed to fetch features: ${res.status} ${res.statusText}\\n${text}`);\n process.exit(1);\n }\n\n const features = (await res.json()) as Feature[];\n const typeByKey = new Map<string, \"boolean\" | \"limit\" | \"unknown\">();\n const trackingByKey = new Map<string, \"tracked\" | \"untracked\" | \"unknown\">();\n\n for (const feature of features ?? []) {\n if (!feature?.featureKey) continue;\n const key = feature.featureKey;\n const nextType = feature.type === \"boolean\" || feature.type === \"limit\" ? feature.type : \"unknown\";\n const currentType = typeByKey.get(key);\n if (!currentType) {\n typeByKey.set(key, nextType);\n } else if (currentType !== nextType) {\n typeByKey.set(key, \"unknown\");\n }\n\n if (nextType !== \"limit\") continue;\n\n const nextTracking =\n feature.tracksUsage === true\n ? \"tracked\"\n : feature.tracksUsage === false\n ? \"untracked\"\n : \"unknown\";\n const currentTracking = trackingByKey.get(key);\n if (!currentTracking) {\n trackingByKey.set(key, nextTracking);\n continue;\n }\n if (currentTracking !== nextTracking) {\n trackingByKey.set(key, \"unknown\");\n }\n }\n\n const keys = [...typeByKey.keys()].sort();\n const union = keys.length ? keys.map((k) => JSON.stringify(k)).join(\" | \") : \"never\";\n const limitKeys = keys.filter((key) => typeByKey.get(key) === \"limit\");\n const limitUnion = limitKeys.length ? limitKeys.map((k) => JSON.stringify(k)).join(\" | \") : \"never\";\n const mapLines = keys.map((key) => {\n const featureType = typeByKey.get(key);\n const accessType =\n featureType === \"boolean\"\n ? \"BooleanFeatureAccess\"\n : featureType === \"limit\"\n ? trackingByKey.get(key) === \"tracked\"\n ? \"TrackedLimitFeatureAccess\"\n : trackingByKey.get(key) === \"untracked\"\n ? \"UntrackedLimitFeatureAccess\"\n : \"LimitFeatureAccess\"\n : \"FeatureAccessEntry\";\n return ` ${JSON.stringify(key)}: ${accessType};`;\n });\n\n const content = `// Auto-generated by PriceOS (priceos generate-types). Do not edit.\nexport type FeatureKey = ${union};\nexport type LimitFeatureKey = ${limitUnion};\nexport type BooleanFeatureAccess = {\n type: \"boolean\";\n hasAccess: boolean;\n};\nexport type LimitFeatureUsage = {\n used: number;\n remaining: number | null;\n bonusRemaining: number;\n bonusUsed: number;\n resetsWhen: \"billing_period\" | \"calendar\";\n resetType: \"never\" | \"day\" | \"week\" | \"month\" | \"year\";\n nextReset: number | null;\n lastReset: number | null;\n};\nexport type TrackedLimitFeatureAccess = {\n type: \"limit\";\n hasAccess: boolean;\n isUnlimited: boolean;\n limit: number | null;\n usage: LimitFeatureUsage;\n};\nexport type UntrackedLimitFeatureAccess = {\n type: \"limit\";\n hasAccess: boolean;\n isUnlimited: boolean;\n limit: number | null;\n};\nexport type LimitFeatureAccess = TrackedLimitFeatureAccess | UntrackedLimitFeatureAccess;\nexport type FeatureAccessEntry = BooleanFeatureAccess | LimitFeatureAccess;\nexport type FeatureAccessMap = {\n${mapLines.join(\"\\n\")}\n};\n`;\n\n await fs.mkdir(path.dirname(outPath), { recursive: true });\n await fs.writeFile(outPath, content, \"utf8\");\n\n console.log(`Generated ${outDisplay} (${keys.length} feature keys)`);\n}\n\nmain().catch((e) => {\n console.error(e);\n process.exit(1);\n});\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -80,7 +80,16 @@ interface paths {
80
80
  * "type": "limit",
81
81
  * "limit": 1000,
82
82
  * "isUnlimited": false,
83
- * "used": 120
83
+ * "usage": {
84
+ * "used": 120,
85
+ * "remaining": 880,
86
+ * "bonusRemaining": 25,
87
+ * "bonusUsed": 5,
88
+ * "resetsWhen": "billing_period",
89
+ * "resetType": "month",
90
+ * "nextReset": 1738368000000,
91
+ * "lastReset": 1735689600000
92
+ * }
84
93
  * },
85
94
  * "team_seats": {
86
95
  * "hasAccess": true,
@@ -196,14 +205,31 @@ interface paths {
196
205
  isUnlimited: boolean;
197
206
  /** @description Limit for the feature, when applicable. */
198
207
  limit: number | null;
199
- /** @description Usage consumed for the feature. */
200
- used: number;
201
- /** @description Remaining base limit (limit - used). */
202
- remaining: number | null;
203
- /** @description Remaining bonus amount. */
204
- bonusRemaining: number;
205
- /** @description Bonus amount consumed. */
206
- bonusUsed: number;
208
+ /** @description Usage details for tracked features. */
209
+ usage?: {
210
+ /** @description Usage consumed for the feature. */
211
+ used: number;
212
+ /** @description Remaining base limit (limit - used). */
213
+ remaining: number | null;
214
+ /** @description Remaining bonus amount. */
215
+ bonusRemaining: number;
216
+ /** @description Bonus amount consumed. */
217
+ bonusUsed: number;
218
+ /**
219
+ * @description When usage resets are anchored.
220
+ * @enum {string}
221
+ */
222
+ resetsWhen: "billing_period" | "calendar";
223
+ /**
224
+ * @description How frequently usage resets.
225
+ * @enum {string}
226
+ */
227
+ resetType: "never" | "day" | "week" | "month" | "year";
228
+ /** @description Unix timestamp (ms) for the next reset, when applicable. */
229
+ nextReset: number | null;
230
+ /** @description Unix timestamp (ms) for the last reset, when applicable. */
231
+ lastReset: number | null;
232
+ };
207
233
  };
208
234
  };
209
235
  /** @description Customer bonuses. */
@@ -355,7 +381,16 @@ interface paths {
355
381
  * "type": "limit",
356
382
  * "limit": 1000,
357
383
  * "isUnlimited": false,
358
- * "used": 120
384
+ * "usage": {
385
+ * "used": 120,
386
+ * "remaining": 880,
387
+ * "bonusRemaining": 25,
388
+ * "bonusUsed": 5,
389
+ * "resetsWhen": "billing_period",
390
+ * "resetType": "month",
391
+ * "nextReset": 1738368000000,
392
+ * "lastReset": 1735689600000
393
+ * }
359
394
  * },
360
395
  * "team_seats": {
361
396
  * "hasAccess": true,
@@ -471,14 +506,31 @@ interface paths {
471
506
  isUnlimited: boolean;
472
507
  /** @description Limit for the feature, when applicable. */
473
508
  limit: number | null;
474
- /** @description Usage consumed for the feature. */
475
- used: number;
476
- /** @description Remaining base limit (limit - used). */
477
- remaining: number | null;
478
- /** @description Remaining bonus amount. */
479
- bonusRemaining: number;
480
- /** @description Bonus amount consumed. */
481
- bonusUsed: number;
509
+ /** @description Usage details for tracked features. */
510
+ usage?: {
511
+ /** @description Usage consumed for the feature. */
512
+ used: number;
513
+ /** @description Remaining base limit (limit - used). */
514
+ remaining: number | null;
515
+ /** @description Remaining bonus amount. */
516
+ bonusRemaining: number;
517
+ /** @description Bonus amount consumed. */
518
+ bonusUsed: number;
519
+ /**
520
+ * @description When usage resets are anchored.
521
+ * @enum {string}
522
+ */
523
+ resetsWhen: "billing_period" | "calendar";
524
+ /**
525
+ * @description How frequently usage resets.
526
+ * @enum {string}
527
+ */
528
+ resetType: "never" | "day" | "week" | "month" | "year";
529
+ /** @description Unix timestamp (ms) for the next reset, when applicable. */
530
+ nextReset: number | null;
531
+ /** @description Unix timestamp (ms) for the last reset, when applicable. */
532
+ lastReset: number | null;
533
+ };
482
534
  };
483
535
  };
484
536
  /** @description Customer bonuses. */
@@ -737,7 +789,16 @@ interface paths {
737
789
  * "type": "limit",
738
790
  * "limit": 1000,
739
791
  * "isUnlimited": false,
740
- * "used": 120
792
+ * "usage": {
793
+ * "used": 120,
794
+ * "remaining": 880,
795
+ * "bonusRemaining": 25,
796
+ * "bonusUsed": 5,
797
+ * "resetsWhen": "billing_period",
798
+ * "resetType": "month",
799
+ * "nextReset": 1738368000000,
800
+ * "lastReset": 1735689600000
801
+ * }
741
802
  * },
742
803
  * "team_seats": {
743
804
  * "hasAccess": true,
@@ -853,14 +914,31 @@ interface paths {
853
914
  isUnlimited: boolean;
854
915
  /** @description Limit for the feature, when applicable. */
855
916
  limit: number | null;
856
- /** @description Usage consumed for the feature. */
857
- used: number;
858
- /** @description Remaining base limit (limit - used). */
859
- remaining: number | null;
860
- /** @description Remaining bonus amount. */
861
- bonusRemaining: number;
862
- /** @description Bonus amount consumed. */
863
- bonusUsed: number;
917
+ /** @description Usage details for tracked features. */
918
+ usage?: {
919
+ /** @description Usage consumed for the feature. */
920
+ used: number;
921
+ /** @description Remaining base limit (limit - used). */
922
+ remaining: number | null;
923
+ /** @description Remaining bonus amount. */
924
+ bonusRemaining: number;
925
+ /** @description Bonus amount consumed. */
926
+ bonusUsed: number;
927
+ /**
928
+ * @description When usage resets are anchored.
929
+ * @enum {string}
930
+ */
931
+ resetsWhen: "billing_period" | "calendar";
932
+ /**
933
+ * @description How frequently usage resets.
934
+ * @enum {string}
935
+ */
936
+ resetType: "never" | "day" | "week" | "month" | "year";
937
+ /** @description Unix timestamp (ms) for the next reset, when applicable. */
938
+ nextReset: number | null;
939
+ /** @description Unix timestamp (ms) for the last reset, when applicable. */
940
+ lastReset: number | null;
941
+ };
864
942
  };
865
943
  };
866
944
  /** @description Customer bonuses. */
@@ -1032,7 +1110,16 @@ interface paths {
1032
1110
  * "type": "limit",
1033
1111
  * "limit": 1000,
1034
1112
  * "isUnlimited": false,
1035
- * "used": 120
1113
+ * "usage": {
1114
+ * "used": 120,
1115
+ * "remaining": 880,
1116
+ * "bonusRemaining": 25,
1117
+ * "bonusUsed": 5,
1118
+ * "resetsWhen": "billing_period",
1119
+ * "resetType": "month",
1120
+ * "nextReset": 1738368000000,
1121
+ * "lastReset": 1735689600000
1122
+ * }
1036
1123
  * },
1037
1124
  * "team_seats": {
1038
1125
  * "hasAccess": true,
@@ -1148,14 +1235,31 @@ interface paths {
1148
1235
  isUnlimited: boolean;
1149
1236
  /** @description Limit for the feature, when applicable. */
1150
1237
  limit: number | null;
1151
- /** @description Usage consumed for the feature. */
1152
- used: number;
1153
- /** @description Remaining base limit (limit - used). */
1154
- remaining: number | null;
1155
- /** @description Remaining bonus amount. */
1156
- bonusRemaining: number;
1157
- /** @description Bonus amount consumed. */
1158
- bonusUsed: number;
1238
+ /** @description Usage details for tracked features. */
1239
+ usage?: {
1240
+ /** @description Usage consumed for the feature. */
1241
+ used: number;
1242
+ /** @description Remaining base limit (limit - used). */
1243
+ remaining: number | null;
1244
+ /** @description Remaining bonus amount. */
1245
+ bonusRemaining: number;
1246
+ /** @description Bonus amount consumed. */
1247
+ bonusUsed: number;
1248
+ /**
1249
+ * @description When usage resets are anchored.
1250
+ * @enum {string}
1251
+ */
1252
+ resetsWhen: "billing_period" | "calendar";
1253
+ /**
1254
+ * @description How frequently usage resets.
1255
+ * @enum {string}
1256
+ */
1257
+ resetType: "never" | "day" | "week" | "month" | "year";
1258
+ /** @description Unix timestamp (ms) for the next reset, when applicable. */
1259
+ nextReset: number | null;
1260
+ /** @description Unix timestamp (ms) for the last reset, when applicable. */
1261
+ lastReset: number | null;
1262
+ };
1159
1263
  };
1160
1264
  };
1161
1265
  /** @description Customer bonuses. */
@@ -1294,7 +1398,16 @@ interface paths {
1294
1398
  * "type": "limit",
1295
1399
  * "limit": 1000,
1296
1400
  * "isUnlimited": false,
1297
- * "used": 120
1401
+ * "usage": {
1402
+ * "used": 120,
1403
+ * "remaining": 880,
1404
+ * "bonusRemaining": 25,
1405
+ * "bonusUsed": 5,
1406
+ * "resetsWhen": "billing_period",
1407
+ * "resetType": "month",
1408
+ * "nextReset": 1738368000000,
1409
+ * "lastReset": 1735689600000
1410
+ * }
1298
1411
  * },
1299
1412
  * "team_seats": {
1300
1413
  * "hasAccess": true,
@@ -1323,14 +1436,31 @@ interface paths {
1323
1436
  isUnlimited: boolean;
1324
1437
  /** @description Limit for the feature, when applicable. */
1325
1438
  limit: number | null;
1326
- /** @description Usage consumed for the feature. */
1327
- used: number;
1328
- /** @description Remaining base limit (limit - used). */
1329
- remaining: number | null;
1330
- /** @description Remaining bonus amount. */
1331
- bonusRemaining: number;
1332
- /** @description Bonus amount consumed. */
1333
- bonusUsed: number;
1439
+ /** @description Usage details for tracked features. */
1440
+ usage?: {
1441
+ /** @description Usage consumed for the feature. */
1442
+ used: number;
1443
+ /** @description Remaining base limit (limit - used). */
1444
+ remaining: number | null;
1445
+ /** @description Remaining bonus amount. */
1446
+ bonusRemaining: number;
1447
+ /** @description Bonus amount consumed. */
1448
+ bonusUsed: number;
1449
+ /**
1450
+ * @description When usage resets are anchored.
1451
+ * @enum {string}
1452
+ */
1453
+ resetsWhen: "billing_period" | "calendar";
1454
+ /**
1455
+ * @description How frequently usage resets.
1456
+ * @enum {string}
1457
+ */
1458
+ resetType: "never" | "day" | "week" | "month" | "year";
1459
+ /** @description Unix timestamp (ms) for the next reset, when applicable. */
1460
+ nextReset: number | null;
1461
+ /** @description Unix timestamp (ms) for the last reset, when applicable. */
1462
+ lastReset: number | null;
1463
+ };
1334
1464
  };
1335
1465
  };
1336
1466
  };
@@ -2583,13 +2713,11 @@ type LinkCustomerResponse<TFeatureAccessMap = GetFeatureAccessResponse> = WithFe
2583
2713
  type GetFeatureAccessResponse = paths["/v1/feature-access"]["get"]["responses"][200]["content"]["application/json"];
2584
2714
  type IsAny<T> = 0 extends (1 & T) ? true : false;
2585
2715
  type LimitFeatureKeyFromEntries<TFeatureAccessMap> = ({
2586
- [K in keyof TFeatureAccessMap]: K extends "__limitFeatureKey" ? never : TFeatureAccessMap[K] extends {
2716
+ [K in keyof TFeatureAccessMap]: TFeatureAccessMap[K] extends {
2587
2717
  type: "limit";
2588
2718
  } ? K : never;
2589
2719
  }[keyof TFeatureAccessMap] & string);
2590
- type LimitFeatureKeyFromAccessMap<TFeatureAccessMap> = IsAny<TFeatureAccessMap> extends true ? string : TFeatureAccessMap extends {
2591
- __limitFeatureKey?: infer K;
2592
- } ? IsAny<K> extends true ? LimitFeatureKeyFromEntries<TFeatureAccessMap> : Extract<K, string> extends never ? LimitFeatureKeyFromEntries<TFeatureAccessMap> : Extract<K, string> : LimitFeatureKeyFromEntries<TFeatureAccessMap>;
2720
+ type LimitFeatureKeyFromAccessMap<TFeatureAccessMap> = IsAny<TFeatureAccessMap> extends true ? string : LimitFeatureKeyFromEntries<TFeatureAccessMap> extends never ? string : LimitFeatureKeyFromEntries<TFeatureAccessMap>;
2593
2721
  type TrackUsageBodyBase = paths["/v1/usage"]["post"]["requestBody"]["content"]["application/json"];
2594
2722
  type TrackUsageBody<TFeatureKey extends string = TrackUsageBodyBase["featureKey"]> = Omit<TrackUsageBodyBase, "featureKey"> & {
2595
2723
  featureKey: TFeatureKey;
package/dist/index.d.ts CHANGED
@@ -80,7 +80,16 @@ interface paths {
80
80
  * "type": "limit",
81
81
  * "limit": 1000,
82
82
  * "isUnlimited": false,
83
- * "used": 120
83
+ * "usage": {
84
+ * "used": 120,
85
+ * "remaining": 880,
86
+ * "bonusRemaining": 25,
87
+ * "bonusUsed": 5,
88
+ * "resetsWhen": "billing_period",
89
+ * "resetType": "month",
90
+ * "nextReset": 1738368000000,
91
+ * "lastReset": 1735689600000
92
+ * }
84
93
  * },
85
94
  * "team_seats": {
86
95
  * "hasAccess": true,
@@ -196,14 +205,31 @@ interface paths {
196
205
  isUnlimited: boolean;
197
206
  /** @description Limit for the feature, when applicable. */
198
207
  limit: number | null;
199
- /** @description Usage consumed for the feature. */
200
- used: number;
201
- /** @description Remaining base limit (limit - used). */
202
- remaining: number | null;
203
- /** @description Remaining bonus amount. */
204
- bonusRemaining: number;
205
- /** @description Bonus amount consumed. */
206
- bonusUsed: number;
208
+ /** @description Usage details for tracked features. */
209
+ usage?: {
210
+ /** @description Usage consumed for the feature. */
211
+ used: number;
212
+ /** @description Remaining base limit (limit - used). */
213
+ remaining: number | null;
214
+ /** @description Remaining bonus amount. */
215
+ bonusRemaining: number;
216
+ /** @description Bonus amount consumed. */
217
+ bonusUsed: number;
218
+ /**
219
+ * @description When usage resets are anchored.
220
+ * @enum {string}
221
+ */
222
+ resetsWhen: "billing_period" | "calendar";
223
+ /**
224
+ * @description How frequently usage resets.
225
+ * @enum {string}
226
+ */
227
+ resetType: "never" | "day" | "week" | "month" | "year";
228
+ /** @description Unix timestamp (ms) for the next reset, when applicable. */
229
+ nextReset: number | null;
230
+ /** @description Unix timestamp (ms) for the last reset, when applicable. */
231
+ lastReset: number | null;
232
+ };
207
233
  };
208
234
  };
209
235
  /** @description Customer bonuses. */
@@ -355,7 +381,16 @@ interface paths {
355
381
  * "type": "limit",
356
382
  * "limit": 1000,
357
383
  * "isUnlimited": false,
358
- * "used": 120
384
+ * "usage": {
385
+ * "used": 120,
386
+ * "remaining": 880,
387
+ * "bonusRemaining": 25,
388
+ * "bonusUsed": 5,
389
+ * "resetsWhen": "billing_period",
390
+ * "resetType": "month",
391
+ * "nextReset": 1738368000000,
392
+ * "lastReset": 1735689600000
393
+ * }
359
394
  * },
360
395
  * "team_seats": {
361
396
  * "hasAccess": true,
@@ -471,14 +506,31 @@ interface paths {
471
506
  isUnlimited: boolean;
472
507
  /** @description Limit for the feature, when applicable. */
473
508
  limit: number | null;
474
- /** @description Usage consumed for the feature. */
475
- used: number;
476
- /** @description Remaining base limit (limit - used). */
477
- remaining: number | null;
478
- /** @description Remaining bonus amount. */
479
- bonusRemaining: number;
480
- /** @description Bonus amount consumed. */
481
- bonusUsed: number;
509
+ /** @description Usage details for tracked features. */
510
+ usage?: {
511
+ /** @description Usage consumed for the feature. */
512
+ used: number;
513
+ /** @description Remaining base limit (limit - used). */
514
+ remaining: number | null;
515
+ /** @description Remaining bonus amount. */
516
+ bonusRemaining: number;
517
+ /** @description Bonus amount consumed. */
518
+ bonusUsed: number;
519
+ /**
520
+ * @description When usage resets are anchored.
521
+ * @enum {string}
522
+ */
523
+ resetsWhen: "billing_period" | "calendar";
524
+ /**
525
+ * @description How frequently usage resets.
526
+ * @enum {string}
527
+ */
528
+ resetType: "never" | "day" | "week" | "month" | "year";
529
+ /** @description Unix timestamp (ms) for the next reset, when applicable. */
530
+ nextReset: number | null;
531
+ /** @description Unix timestamp (ms) for the last reset, when applicable. */
532
+ lastReset: number | null;
533
+ };
482
534
  };
483
535
  };
484
536
  /** @description Customer bonuses. */
@@ -737,7 +789,16 @@ interface paths {
737
789
  * "type": "limit",
738
790
  * "limit": 1000,
739
791
  * "isUnlimited": false,
740
- * "used": 120
792
+ * "usage": {
793
+ * "used": 120,
794
+ * "remaining": 880,
795
+ * "bonusRemaining": 25,
796
+ * "bonusUsed": 5,
797
+ * "resetsWhen": "billing_period",
798
+ * "resetType": "month",
799
+ * "nextReset": 1738368000000,
800
+ * "lastReset": 1735689600000
801
+ * }
741
802
  * },
742
803
  * "team_seats": {
743
804
  * "hasAccess": true,
@@ -853,14 +914,31 @@ interface paths {
853
914
  isUnlimited: boolean;
854
915
  /** @description Limit for the feature, when applicable. */
855
916
  limit: number | null;
856
- /** @description Usage consumed for the feature. */
857
- used: number;
858
- /** @description Remaining base limit (limit - used). */
859
- remaining: number | null;
860
- /** @description Remaining bonus amount. */
861
- bonusRemaining: number;
862
- /** @description Bonus amount consumed. */
863
- bonusUsed: number;
917
+ /** @description Usage details for tracked features. */
918
+ usage?: {
919
+ /** @description Usage consumed for the feature. */
920
+ used: number;
921
+ /** @description Remaining base limit (limit - used). */
922
+ remaining: number | null;
923
+ /** @description Remaining bonus amount. */
924
+ bonusRemaining: number;
925
+ /** @description Bonus amount consumed. */
926
+ bonusUsed: number;
927
+ /**
928
+ * @description When usage resets are anchored.
929
+ * @enum {string}
930
+ */
931
+ resetsWhen: "billing_period" | "calendar";
932
+ /**
933
+ * @description How frequently usage resets.
934
+ * @enum {string}
935
+ */
936
+ resetType: "never" | "day" | "week" | "month" | "year";
937
+ /** @description Unix timestamp (ms) for the next reset, when applicable. */
938
+ nextReset: number | null;
939
+ /** @description Unix timestamp (ms) for the last reset, when applicable. */
940
+ lastReset: number | null;
941
+ };
864
942
  };
865
943
  };
866
944
  /** @description Customer bonuses. */
@@ -1032,7 +1110,16 @@ interface paths {
1032
1110
  * "type": "limit",
1033
1111
  * "limit": 1000,
1034
1112
  * "isUnlimited": false,
1035
- * "used": 120
1113
+ * "usage": {
1114
+ * "used": 120,
1115
+ * "remaining": 880,
1116
+ * "bonusRemaining": 25,
1117
+ * "bonusUsed": 5,
1118
+ * "resetsWhen": "billing_period",
1119
+ * "resetType": "month",
1120
+ * "nextReset": 1738368000000,
1121
+ * "lastReset": 1735689600000
1122
+ * }
1036
1123
  * },
1037
1124
  * "team_seats": {
1038
1125
  * "hasAccess": true,
@@ -1148,14 +1235,31 @@ interface paths {
1148
1235
  isUnlimited: boolean;
1149
1236
  /** @description Limit for the feature, when applicable. */
1150
1237
  limit: number | null;
1151
- /** @description Usage consumed for the feature. */
1152
- used: number;
1153
- /** @description Remaining base limit (limit - used). */
1154
- remaining: number | null;
1155
- /** @description Remaining bonus amount. */
1156
- bonusRemaining: number;
1157
- /** @description Bonus amount consumed. */
1158
- bonusUsed: number;
1238
+ /** @description Usage details for tracked features. */
1239
+ usage?: {
1240
+ /** @description Usage consumed for the feature. */
1241
+ used: number;
1242
+ /** @description Remaining base limit (limit - used). */
1243
+ remaining: number | null;
1244
+ /** @description Remaining bonus amount. */
1245
+ bonusRemaining: number;
1246
+ /** @description Bonus amount consumed. */
1247
+ bonusUsed: number;
1248
+ /**
1249
+ * @description When usage resets are anchored.
1250
+ * @enum {string}
1251
+ */
1252
+ resetsWhen: "billing_period" | "calendar";
1253
+ /**
1254
+ * @description How frequently usage resets.
1255
+ * @enum {string}
1256
+ */
1257
+ resetType: "never" | "day" | "week" | "month" | "year";
1258
+ /** @description Unix timestamp (ms) for the next reset, when applicable. */
1259
+ nextReset: number | null;
1260
+ /** @description Unix timestamp (ms) for the last reset, when applicable. */
1261
+ lastReset: number | null;
1262
+ };
1159
1263
  };
1160
1264
  };
1161
1265
  /** @description Customer bonuses. */
@@ -1294,7 +1398,16 @@ interface paths {
1294
1398
  * "type": "limit",
1295
1399
  * "limit": 1000,
1296
1400
  * "isUnlimited": false,
1297
- * "used": 120
1401
+ * "usage": {
1402
+ * "used": 120,
1403
+ * "remaining": 880,
1404
+ * "bonusRemaining": 25,
1405
+ * "bonusUsed": 5,
1406
+ * "resetsWhen": "billing_period",
1407
+ * "resetType": "month",
1408
+ * "nextReset": 1738368000000,
1409
+ * "lastReset": 1735689600000
1410
+ * }
1298
1411
  * },
1299
1412
  * "team_seats": {
1300
1413
  * "hasAccess": true,
@@ -1323,14 +1436,31 @@ interface paths {
1323
1436
  isUnlimited: boolean;
1324
1437
  /** @description Limit for the feature, when applicable. */
1325
1438
  limit: number | null;
1326
- /** @description Usage consumed for the feature. */
1327
- used: number;
1328
- /** @description Remaining base limit (limit - used). */
1329
- remaining: number | null;
1330
- /** @description Remaining bonus amount. */
1331
- bonusRemaining: number;
1332
- /** @description Bonus amount consumed. */
1333
- bonusUsed: number;
1439
+ /** @description Usage details for tracked features. */
1440
+ usage?: {
1441
+ /** @description Usage consumed for the feature. */
1442
+ used: number;
1443
+ /** @description Remaining base limit (limit - used). */
1444
+ remaining: number | null;
1445
+ /** @description Remaining bonus amount. */
1446
+ bonusRemaining: number;
1447
+ /** @description Bonus amount consumed. */
1448
+ bonusUsed: number;
1449
+ /**
1450
+ * @description When usage resets are anchored.
1451
+ * @enum {string}
1452
+ */
1453
+ resetsWhen: "billing_period" | "calendar";
1454
+ /**
1455
+ * @description How frequently usage resets.
1456
+ * @enum {string}
1457
+ */
1458
+ resetType: "never" | "day" | "week" | "month" | "year";
1459
+ /** @description Unix timestamp (ms) for the next reset, when applicable. */
1460
+ nextReset: number | null;
1461
+ /** @description Unix timestamp (ms) for the last reset, when applicable. */
1462
+ lastReset: number | null;
1463
+ };
1334
1464
  };
1335
1465
  };
1336
1466
  };
@@ -2583,13 +2713,11 @@ type LinkCustomerResponse<TFeatureAccessMap = GetFeatureAccessResponse> = WithFe
2583
2713
  type GetFeatureAccessResponse = paths["/v1/feature-access"]["get"]["responses"][200]["content"]["application/json"];
2584
2714
  type IsAny<T> = 0 extends (1 & T) ? true : false;
2585
2715
  type LimitFeatureKeyFromEntries<TFeatureAccessMap> = ({
2586
- [K in keyof TFeatureAccessMap]: K extends "__limitFeatureKey" ? never : TFeatureAccessMap[K] extends {
2716
+ [K in keyof TFeatureAccessMap]: TFeatureAccessMap[K] extends {
2587
2717
  type: "limit";
2588
2718
  } ? K : never;
2589
2719
  }[keyof TFeatureAccessMap] & string);
2590
- type LimitFeatureKeyFromAccessMap<TFeatureAccessMap> = IsAny<TFeatureAccessMap> extends true ? string : TFeatureAccessMap extends {
2591
- __limitFeatureKey?: infer K;
2592
- } ? IsAny<K> extends true ? LimitFeatureKeyFromEntries<TFeatureAccessMap> : Extract<K, string> extends never ? LimitFeatureKeyFromEntries<TFeatureAccessMap> : Extract<K, string> : LimitFeatureKeyFromEntries<TFeatureAccessMap>;
2720
+ type LimitFeatureKeyFromAccessMap<TFeatureAccessMap> = IsAny<TFeatureAccessMap> extends true ? string : LimitFeatureKeyFromEntries<TFeatureAccessMap> extends never ? string : LimitFeatureKeyFromEntries<TFeatureAccessMap>;
2593
2721
  type TrackUsageBodyBase = paths["/v1/usage"]["post"]["requestBody"]["content"]["application/json"];
2594
2722
  type TrackUsageBody<TFeatureKey extends string = TrackUsageBodyBase["featureKey"]> = Omit<TrackUsageBodyBase, "featureKey"> & {
2595
2723
  featureKey: TFeatureKey;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "priceos",
3
- "version": "0.0.41",
3
+ "version": "0.0.43",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",