@stardeck-customer-apps/data-store-sdk 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/SKILL.md +8 -1
- package/dist/chunk-EWWQPGFI.mjs +662 -0
- package/dist/chunk-FEKROS4B.mjs +66 -0
- package/dist/cli/bin.d.mts +1 -0
- package/dist/cli/bin.d.ts +1 -0
- package/dist/cli/bin.js +729 -0
- package/dist/cli/bin.mjs +11 -0
- package/dist/cli/generate-types.d.mts +27 -2
- package/dist/cli/generate-types.d.ts +27 -2
- package/dist/cli/generate-types.js +121 -27
- package/dist/cli/generate-types.mjs +15 -608
- package/dist/server/index.mjs +8 -63
- package/package.json +6 -4
package/dist/cli/bin.mjs
ADDED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
1
|
declare function toPascalCase(name: string): string;
|
|
3
2
|
|
|
4
3
|
interface ColumnInfo {
|
|
@@ -13,6 +12,8 @@ declare function pgTypeToTs(pgType: string): string;
|
|
|
13
12
|
|
|
14
13
|
type ParsedCliArgs = {
|
|
15
14
|
connectionString: string | undefined;
|
|
15
|
+
/** `--store`: which manifest entry to use when the app has several connected. */
|
|
16
|
+
store: string | undefined;
|
|
16
17
|
outputPath: string;
|
|
17
18
|
schemaOutputPath: string | undefined;
|
|
18
19
|
emitSchema: boolean;
|
|
@@ -45,6 +46,30 @@ type RunGenerateTypesOptions = {
|
|
|
45
46
|
* so tests can stub the pool without a live database.
|
|
46
47
|
*/
|
|
47
48
|
declare function runGenerateTypes(options: RunGenerateTypesOptions): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* The connection string for the store the app is pointed at, from the manifest
|
|
51
|
+
* the app runtime itself resolves stores from. `--store` picks one entry the way
|
|
52
|
+
* `resolveDataStore` does (id, binding key, slug, name); otherwise the app's
|
|
53
|
+
* single database store is the answer, and anything else is an error the
|
|
54
|
+
* operator can act on. Storage stores carry no url and never count.
|
|
55
|
+
*/
|
|
56
|
+
declare function connectionStringFromManifest(store: string | undefined): {
|
|
57
|
+
url: string;
|
|
58
|
+
} | {
|
|
59
|
+
error: string;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Load `./.env.local` the way the app's `next dev` reads it. `env:pull` writes
|
|
63
|
+
* the file for `@next/env` — dotenv parse followed by dotenv-expand — and
|
|
64
|
+
* escapes every `$` as `\$` so expand leaves the value alone; Node's parser
|
|
65
|
+
* keeps that backslash, which turns a manifest holding a `$` (a store name, a
|
|
66
|
+
* password) into invalid JSON. Undo the one escape so the manifest is the JSON
|
|
67
|
+
* the app sees. Shell values win over the file, like `node --env-file`.
|
|
68
|
+
*
|
|
69
|
+
* ponytail: no `$VAR` expansion of hand-edited lines; `env:pull` never writes
|
|
70
|
+
* one. Add dotenv-expand if a file ever needs it.
|
|
71
|
+
*/
|
|
72
|
+
declare function loadEnvLocal(cwd: string): void;
|
|
48
73
|
declare function main(argv?: string[]): Promise<void>;
|
|
49
74
|
|
|
50
|
-
export { type ColumnInfo, PG_TYPE_MAP, type ParsedCliArgs, type RunGenerateTypesOptions, generateTypeScript, introspectSchema, main, parseCliArgs, pgTypeToTs, runGenerateTypes, toPascalCase };
|
|
75
|
+
export { type ColumnInfo, PG_TYPE_MAP, type ParsedCliArgs, type RunGenerateTypesOptions, connectionStringFromManifest, generateTypeScript, introspectSchema, loadEnvLocal, main, parseCliArgs, pgTypeToTs, runGenerateTypes, toPascalCase };
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
1
|
declare function toPascalCase(name: string): string;
|
|
3
2
|
|
|
4
3
|
interface ColumnInfo {
|
|
@@ -13,6 +12,8 @@ declare function pgTypeToTs(pgType: string): string;
|
|
|
13
12
|
|
|
14
13
|
type ParsedCliArgs = {
|
|
15
14
|
connectionString: string | undefined;
|
|
15
|
+
/** `--store`: which manifest entry to use when the app has several connected. */
|
|
16
|
+
store: string | undefined;
|
|
16
17
|
outputPath: string;
|
|
17
18
|
schemaOutputPath: string | undefined;
|
|
18
19
|
emitSchema: boolean;
|
|
@@ -45,6 +46,30 @@ type RunGenerateTypesOptions = {
|
|
|
45
46
|
* so tests can stub the pool without a live database.
|
|
46
47
|
*/
|
|
47
48
|
declare function runGenerateTypes(options: RunGenerateTypesOptions): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* The connection string for the store the app is pointed at, from the manifest
|
|
51
|
+
* the app runtime itself resolves stores from. `--store` picks one entry the way
|
|
52
|
+
* `resolveDataStore` does (id, binding key, slug, name); otherwise the app's
|
|
53
|
+
* single database store is the answer, and anything else is an error the
|
|
54
|
+
* operator can act on. Storage stores carry no url and never count.
|
|
55
|
+
*/
|
|
56
|
+
declare function connectionStringFromManifest(store: string | undefined): {
|
|
57
|
+
url: string;
|
|
58
|
+
} | {
|
|
59
|
+
error: string;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Load `./.env.local` the way the app's `next dev` reads it. `env:pull` writes
|
|
63
|
+
* the file for `@next/env` — dotenv parse followed by dotenv-expand — and
|
|
64
|
+
* escapes every `$` as `\$` so expand leaves the value alone; Node's parser
|
|
65
|
+
* keeps that backslash, which turns a manifest holding a `$` (a store name, a
|
|
66
|
+
* password) into invalid JSON. Undo the one escape so the manifest is the JSON
|
|
67
|
+
* the app sees. Shell values win over the file, like `node --env-file`.
|
|
68
|
+
*
|
|
69
|
+
* ponytail: no `$VAR` expansion of hand-edited lines; `env:pull` never writes
|
|
70
|
+
* one. Add dotenv-expand if a file ever needs it.
|
|
71
|
+
*/
|
|
72
|
+
declare function loadEnvLocal(cwd: string): void;
|
|
48
73
|
declare function main(argv?: string[]): Promise<void>;
|
|
49
74
|
|
|
50
|
-
export { type ColumnInfo, PG_TYPE_MAP, type ParsedCliArgs, type RunGenerateTypesOptions, generateTypeScript, introspectSchema, main, parseCliArgs, pgTypeToTs, runGenerateTypes, toPascalCase };
|
|
75
|
+
export { type ColumnInfo, PG_TYPE_MAP, type ParsedCliArgs, type RunGenerateTypesOptions, connectionStringFromManifest, generateTypeScript, introspectSchema, loadEnvLocal, main, parseCliArgs, pgTypeToTs, runGenerateTypes, toPascalCase };
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
1
|
"use strict";
|
|
3
2
|
var __create = Object.create;
|
|
4
3
|
var __defProp = Object.defineProperty;
|
|
@@ -32,8 +31,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
32
31
|
var generate_types_exports = {};
|
|
33
32
|
__export(generate_types_exports, {
|
|
34
33
|
PG_TYPE_MAP: () => PG_TYPE_MAP,
|
|
34
|
+
connectionStringFromManifest: () => connectionStringFromManifest,
|
|
35
35
|
generateTypeScript: () => generateTypeScript,
|
|
36
36
|
introspectSchema: () => introspectSchema,
|
|
37
|
+
loadEnvLocal: () => loadEnvLocal,
|
|
37
38
|
main: () => main,
|
|
38
39
|
parseCliArgs: () => parseCliArgs,
|
|
39
40
|
pgTypeToTs: () => pgTypeToTs,
|
|
@@ -43,9 +44,63 @@ __export(generate_types_exports, {
|
|
|
43
44
|
module.exports = __toCommonJS(generate_types_exports);
|
|
44
45
|
var import_fs2 = require("fs");
|
|
45
46
|
var import_path2 = require("path");
|
|
46
|
-
var
|
|
47
|
+
var import_util = require("util");
|
|
47
48
|
var import_serverless = require("@neondatabase/serverless");
|
|
48
49
|
|
|
50
|
+
// src/server/manifest.ts
|
|
51
|
+
var STARDECK_DATA_STORES_ENV = "STARDECK_DATA_STORES";
|
|
52
|
+
function readEnv(key) {
|
|
53
|
+
if (typeof process !== "undefined" && process.env?.[key]) {
|
|
54
|
+
return process.env[key];
|
|
55
|
+
}
|
|
56
|
+
return void 0;
|
|
57
|
+
}
|
|
58
|
+
function dataStoreSlug(name) {
|
|
59
|
+
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
60
|
+
return slug || "store";
|
|
61
|
+
}
|
|
62
|
+
function readDataStoreManifest() {
|
|
63
|
+
const raw = readEnv(STARDECK_DATA_STORES_ENV);
|
|
64
|
+
if (!raw) return [];
|
|
65
|
+
try {
|
|
66
|
+
const parsed = JSON.parse(raw);
|
|
67
|
+
if (!Array.isArray(parsed)) return [];
|
|
68
|
+
return parsed.filter((e) => {
|
|
69
|
+
if (typeof e !== "object" || e === null) return false;
|
|
70
|
+
const entry = e;
|
|
71
|
+
if (typeof entry.id !== "string" || typeof entry.name !== "string" || typeof entry.slug !== "string") {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
return entry.storeType === "storage" || typeof entry.url === "string";
|
|
75
|
+
});
|
|
76
|
+
} catch {
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function resolveDataStore(ref) {
|
|
81
|
+
return resolveManifestEntry(readDataStoreManifest(), ref);
|
|
82
|
+
}
|
|
83
|
+
function resolveManifestEntry(entries, ref) {
|
|
84
|
+
if (ref.storeId) {
|
|
85
|
+
const byId = entries.find((e) => e.id === ref.storeId);
|
|
86
|
+
if (byId) return byId;
|
|
87
|
+
}
|
|
88
|
+
if (ref.storeName) {
|
|
89
|
+
const target = ref.storeName;
|
|
90
|
+
const byBindingKey = entries.find((e) => e.bindingKey === target);
|
|
91
|
+
if (byBindingKey) return byBindingKey;
|
|
92
|
+
const exact = entries.find((e) => e.slug === target || e.id === target || e.name === target);
|
|
93
|
+
if (exact) return exact;
|
|
94
|
+
const norm = dataStoreSlug(target);
|
|
95
|
+
const byBindingKeyNorm = entries.find((e) => e.bindingKey === norm);
|
|
96
|
+
if (byBindingKeyNorm) return byBindingKeyNorm;
|
|
97
|
+
return entries.find(
|
|
98
|
+
(e) => e.slug === norm || typeof e.name === "string" && dataStoreSlug(e.name) === norm
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return void 0;
|
|
102
|
+
}
|
|
103
|
+
|
|
49
104
|
// src/cli/module-type-slices.ts
|
|
50
105
|
var import_fs = require("fs");
|
|
51
106
|
var import_path = require("path");
|
|
@@ -408,7 +463,6 @@ function generateSchemaSql(snapshot) {
|
|
|
408
463
|
}
|
|
409
464
|
|
|
410
465
|
// src/cli/generate-types.ts
|
|
411
|
-
var import_meta = {};
|
|
412
466
|
var PG_TYPE_MAP = {
|
|
413
467
|
text: "string",
|
|
414
468
|
varchar: "string",
|
|
@@ -445,19 +499,23 @@ function parseCliArgs(argv, options = {}) {
|
|
|
445
499
|
const cwd = options.cwd ?? process.cwd();
|
|
446
500
|
const env = options.env ?? process.env;
|
|
447
501
|
let connectionString = env.DATA_STORE_URL;
|
|
502
|
+
let store;
|
|
448
503
|
let outputPath = "./src/generated/data-store-types.ts";
|
|
449
504
|
let schemaOutputPath;
|
|
450
|
-
let emitSchema =
|
|
505
|
+
let emitSchema = !(0, import_fs2.existsSync)((0, import_path2.resolve)(cwd, "datastore/ledger-order.json"));
|
|
451
506
|
let modulesDir = (0, import_path2.resolve)(cwd, "./src/modules");
|
|
452
507
|
let noModules = false;
|
|
453
508
|
let help = false;
|
|
454
509
|
for (let i = 0; i < argv.length; i++) {
|
|
455
510
|
if (argv[i] === "--connection-string" && argv[i + 1]) {
|
|
456
511
|
connectionString = argv[++i];
|
|
512
|
+
} else if (argv[i] === "--store" && argv[i + 1]) {
|
|
513
|
+
store = argv[++i];
|
|
457
514
|
} else if (argv[i] === "--output" && argv[i + 1]) {
|
|
458
515
|
outputPath = argv[++i];
|
|
459
516
|
} else if (argv[i] === "--schema-output" && argv[i + 1]) {
|
|
460
517
|
schemaOutputPath = argv[++i];
|
|
518
|
+
emitSchema = true;
|
|
461
519
|
} else if (argv[i] === "--no-schema") {
|
|
462
520
|
emitSchema = false;
|
|
463
521
|
} else if (argv[i] === "--modules-dir" && argv[i + 1]) {
|
|
@@ -470,6 +528,7 @@ function parseCliArgs(argv, options = {}) {
|
|
|
470
528
|
}
|
|
471
529
|
return {
|
|
472
530
|
connectionString,
|
|
531
|
+
store,
|
|
473
532
|
outputPath,
|
|
474
533
|
schemaOutputPath,
|
|
475
534
|
emitSchema,
|
|
@@ -602,29 +661,77 @@ async function runGenerateTypes(options) {
|
|
|
602
661
|
}
|
|
603
662
|
}
|
|
604
663
|
}
|
|
664
|
+
function connectionStringFromManifest(store) {
|
|
665
|
+
const databases = readDataStoreManifest().filter((entry) => entry.storeType !== "storage");
|
|
666
|
+
if (store) {
|
|
667
|
+
const match = resolveDataStore({ storeName: store });
|
|
668
|
+
if (!match?.url) {
|
|
669
|
+
return {
|
|
670
|
+
error: `No connected database store matches --store ${store}. Connected: ${listStores(databases)}.`
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
return { url: match.url };
|
|
674
|
+
}
|
|
675
|
+
if (databases.length === 1 && databases[0]?.url) return { url: databases[0].url };
|
|
676
|
+
if (databases.length === 0) {
|
|
677
|
+
return {
|
|
678
|
+
error: "No connected database store found. Run `npm run env:pull` in apps/web to write .env.local, or pass --connection-string."
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
return {
|
|
682
|
+
error: `${databases.length} database stores are connected; pass --store <bindingKey>. Connected: ${listStores(databases)}.`
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
function listStores(entries) {
|
|
686
|
+
return entries.length === 0 ? "none" : entries.map((entry) => entry.bindingKey ?? entry.slug).join(", ");
|
|
687
|
+
}
|
|
688
|
+
function loadEnvLocal(cwd) {
|
|
689
|
+
const path = (0, import_path2.resolve)(cwd, ".env.local");
|
|
690
|
+
let content;
|
|
691
|
+
try {
|
|
692
|
+
content = (0, import_fs2.readFileSync)(path, "utf8");
|
|
693
|
+
} catch (error) {
|
|
694
|
+
if (error.code !== "ENOENT") {
|
|
695
|
+
console.warn(`Warning: could not read ${path}: ${error.message}`);
|
|
696
|
+
}
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
for (const [key, value] of Object.entries((0, import_util.parseEnv)(content))) {
|
|
700
|
+
if (value !== void 0 && process.env[key] === void 0) {
|
|
701
|
+
process.env[key] = value.replace(/\\\$/g, "$");
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
}
|
|
605
705
|
async function main(argv = process.argv.slice(2)) {
|
|
706
|
+
loadEnvLocal(process.cwd());
|
|
606
707
|
const parsed = parseCliArgs(argv);
|
|
607
708
|
if (parsed.help) {
|
|
608
709
|
console.log(`Usage: stardeck-data-store generate-types [options]
|
|
609
710
|
|
|
610
711
|
Options:
|
|
611
|
-
--connection-string <url> Postgres connection string (default: DATA_STORE_URL
|
|
712
|
+
--connection-string <url> Postgres connection string (default: DATA_STORE_URL, else the
|
|
713
|
+
app's connected store from STARDECK_DATA_STORES / .env.local)
|
|
714
|
+
--store <bindingKey> Which connected store to read when the app has several
|
|
612
715
|
--output <path> Output file path (default: ./src/generated/data-store-types.ts)
|
|
613
716
|
--schema-output <path> DDL snapshot path (default: data-store-schema.sql next to --output)
|
|
614
|
-
--no-schema Skip the DDL snapshot used by the test harness
|
|
717
|
+
--no-schema Skip the DDL snapshot used by the test harness (implied when
|
|
718
|
+
datastore/ledger-order.json exists: a Blueprint composes its own)
|
|
615
719
|
--modules-dir <path> Directory containing module folders (default: ./src/modules)
|
|
616
720
|
--no-modules Skip per-module DB slice generation
|
|
617
721
|
--help Show this help message`);
|
|
618
722
|
process.exit(0);
|
|
619
723
|
}
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
)
|
|
624
|
-
|
|
724
|
+
let connectionString = parsed.connectionString;
|
|
725
|
+
if (!connectionString) {
|
|
726
|
+
const resolved = connectionStringFromManifest(parsed.store);
|
|
727
|
+
if ("error" in resolved) {
|
|
728
|
+
console.error(`Error: ${resolved.error}`);
|
|
729
|
+
process.exit(1);
|
|
730
|
+
}
|
|
731
|
+
connectionString = resolved.url;
|
|
625
732
|
}
|
|
626
733
|
await runGenerateTypes({
|
|
627
|
-
connectionString
|
|
734
|
+
connectionString,
|
|
628
735
|
outputPath: parsed.outputPath,
|
|
629
736
|
schemaOutputPath: parsed.schemaOutputPath,
|
|
630
737
|
emitSchema: parsed.emitSchema,
|
|
@@ -632,26 +739,13 @@ Options:
|
|
|
632
739
|
noModules: parsed.noModules
|
|
633
740
|
});
|
|
634
741
|
}
|
|
635
|
-
function isDirectCliRun() {
|
|
636
|
-
const entry = process.argv[1];
|
|
637
|
-
if (!entry) return false;
|
|
638
|
-
try {
|
|
639
|
-
return import_meta.url === (0, import_url.pathToFileURL)((0, import_path2.resolve)(entry)).href;
|
|
640
|
-
} catch {
|
|
641
|
-
return false;
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
if (isDirectCliRun()) {
|
|
645
|
-
main().catch((error) => {
|
|
646
|
-
console.error("Failed to generate types:", error);
|
|
647
|
-
process.exit(1);
|
|
648
|
-
});
|
|
649
|
-
}
|
|
650
742
|
// Annotate the CommonJS export names for ESM import in node:
|
|
651
743
|
0 && (module.exports = {
|
|
652
744
|
PG_TYPE_MAP,
|
|
745
|
+
connectionStringFromManifest,
|
|
653
746
|
generateTypeScript,
|
|
654
747
|
introspectSchema,
|
|
748
|
+
loadEnvLocal,
|
|
655
749
|
main,
|
|
656
750
|
parseCliArgs,
|
|
657
751
|
pgTypeToTs,
|