@myna-sh/cli 0.1.0 → 0.1.3

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tiago Mouta
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # @myna-sh/cli
2
+
3
+ Command-line client for [Myna](https://myna.sh), the agent-native headless CMS.
4
+
5
+ ## Install
6
+
7
+ ```sh
8
+ npm install --global @myna-sh/cli
9
+ ```
10
+
11
+ Or run it without installing:
12
+
13
+ ```sh
14
+ npx @myna-sh/cli --help
15
+ ```
16
+
17
+ ## Authenticate
18
+
19
+ ```sh
20
+ myna login
21
+ ```
22
+
23
+ The CLI opens `app.myna.sh/device`, where you sign in with GitHub and approve the one-time device code. The resulting credential is stored in the macOS Keychain when available, otherwise in a user-only configuration file.
24
+
25
+ ## Start a project
26
+
27
+ ```sh
28
+ myna organizations list
29
+ myna projects list --organization my-organization
30
+ myna link --organization my-organization --project my-project
31
+ myna entries list posts
32
+ ```
33
+
34
+ Run `myna --help` or `myna <command> --help` for the complete command reference. Global flags include `--json`, `--organization`, `--project`, `--token`, and `--api-url`.
35
+
36
+ ## Environment
37
+
38
+ ```text
39
+ MYNA_API_URL API origin; defaults to https://api.myna.sh
40
+ MYNA_TOKEN Scoped API credential
41
+ MYNA_ORGANIZATION Default organization ID or slug
42
+ MYNA_PROJECT Default project ID or slug
43
+ ```
44
+
45
+ ## Links
46
+
47
+ - [Myna](https://myna.sh)
48
+ - Support: [support@myna.sh](mailto:support@myna.sh)
49
+
50
+ ## License
51
+
52
+ MIT
package/dist/dsl.d.ts ADDED
@@ -0,0 +1,276 @@
1
+ /**
2
+ * Canonical schema representation (SPEC 6.2 / 7).
3
+ *
4
+ * These are the normalized, serializable shapes stored as `schema_json`. Field
5
+ * order is significant and preserved as an array; object *keys* are sorted only
6
+ * during canonical stringification for a stable hash.
7
+ */
8
+ type FieldType = "text" | "number" | "boolean" | "date" | "datetime" | "markdown" | "json" | "asset" | "reference" | "list" | "object" | "slug";
9
+ type JsonValue = string | number | boolean | null | JsonValue[] | {
10
+ [key: string]: JsonValue;
11
+ };
12
+ /** UI metadata carried on every field (non-semantic, does not affect validation). */
13
+ interface FieldUi {
14
+ widget?: string;
15
+ placeholder?: string;
16
+ helpText?: string;
17
+ group?: string;
18
+ hidden?: boolean;
19
+ }
20
+ interface FieldBase {
21
+ key: string;
22
+ type: FieldType;
23
+ label: string;
24
+ description?: string;
25
+ required: boolean;
26
+ ui?: FieldUi;
27
+ }
28
+ interface TextField extends FieldBase {
29
+ type: "text";
30
+ multiline: boolean;
31
+ minLength?: number;
32
+ maxLength?: number;
33
+ pattern?: string;
34
+ enum?: string[];
35
+ default?: string;
36
+ }
37
+ interface NumberField extends FieldBase {
38
+ type: "number";
39
+ integer: boolean;
40
+ min?: number;
41
+ max?: number;
42
+ default?: number;
43
+ }
44
+ interface BooleanField extends FieldBase {
45
+ type: "boolean";
46
+ default?: boolean;
47
+ }
48
+ interface DateField extends FieldBase {
49
+ type: "date" | "datetime";
50
+ min?: string;
51
+ max?: string;
52
+ default?: string;
53
+ }
54
+ interface MarkdownField extends FieldBase {
55
+ type: "markdown";
56
+ minLength?: number;
57
+ maxLength?: number;
58
+ default?: string;
59
+ }
60
+ interface JsonField extends FieldBase {
61
+ type: "json";
62
+ default?: JsonValue;
63
+ }
64
+ interface AssetField extends FieldBase {
65
+ type: "asset";
66
+ /** Allowed MIME families, e.g. `image/*`, `application/pdf`. */
67
+ allowed: string[];
68
+ multiple: boolean;
69
+ }
70
+ interface ReferenceField extends FieldBase {
71
+ type: "reference";
72
+ /** Target collection key. */
73
+ target: string;
74
+ multiple: boolean;
75
+ }
76
+ interface SlugField extends FieldBase {
77
+ type: "slug";
78
+ /** Source field key to derive the slug from. */
79
+ from?: string;
80
+ }
81
+ type PrimitiveItem = {
82
+ kind: "text";
83
+ minLength?: number;
84
+ maxLength?: number;
85
+ pattern?: string;
86
+ enum?: string[];
87
+ } | {
88
+ kind: "number";
89
+ integer?: boolean;
90
+ min?: number;
91
+ max?: number;
92
+ } | {
93
+ kind: "boolean";
94
+ } | {
95
+ kind: "date" | "datetime";
96
+ min?: string;
97
+ max?: string;
98
+ } | {
99
+ kind: "markdown";
100
+ minLength?: number;
101
+ maxLength?: number;
102
+ } | {
103
+ kind: "json";
104
+ };
105
+ type ListItem = PrimitiveItem | {
106
+ kind: "reference";
107
+ target: string;
108
+ } | {
109
+ kind: "asset";
110
+ allowed: string[];
111
+ } | {
112
+ kind: "object";
113
+ fields: FieldDef[];
114
+ };
115
+ interface ListField extends FieldBase {
116
+ type: "list";
117
+ item: ListItem;
118
+ minItems?: number;
119
+ maxItems?: number;
120
+ }
121
+ interface ObjectField extends FieldBase {
122
+ type: "object";
123
+ fields: FieldDef[];
124
+ }
125
+ type FieldDef = TextField | NumberField | BooleanField | DateField | MarkdownField | JsonField | AssetField | ReferenceField | SlugField | ListField | ObjectField;
126
+ type CollectionKind = "collection" | "singleton";
127
+ type Visibility = "public" | "private";
128
+ interface SlugConfig {
129
+ from: string;
130
+ required: boolean;
131
+ }
132
+ /** Canonical collection schema (one `collection_versions.schema_json`). */
133
+ interface CollectionSchema {
134
+ name: string;
135
+ label: string;
136
+ kind: CollectionKind;
137
+ visibility: Visibility;
138
+ titleField: string | null;
139
+ slug: SlugConfig | null;
140
+ path: string | null;
141
+ fields: FieldDef[];
142
+ }
143
+ /** Maximum object/list nesting depth (SPEC 6.2). */
144
+ declare const MAX_NESTING_DEPTH = 4;
145
+
146
+ /** A field definition before its `key` is assigned by `collection()`. */
147
+ type FieldInput = DistributiveOmit<FieldDef, "key">;
148
+ type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;
149
+ interface CommonOptions {
150
+ label?: string;
151
+ description?: string;
152
+ required?: boolean;
153
+ ui?: FieldUi;
154
+ }
155
+ interface TextOptions extends CommonOptions {
156
+ multiline?: boolean;
157
+ minLength?: number;
158
+ maxLength?: number;
159
+ pattern?: string;
160
+ enum?: string[];
161
+ default?: string;
162
+ }
163
+ interface NumberOptions extends CommonOptions {
164
+ integer?: boolean;
165
+ min?: number;
166
+ max?: number;
167
+ default?: number;
168
+ }
169
+ interface BooleanOptions extends CommonOptions {
170
+ default?: boolean;
171
+ }
172
+ interface DateOptions extends CommonOptions {
173
+ min?: string;
174
+ max?: string;
175
+ default?: string;
176
+ }
177
+ interface MarkdownOptions extends CommonOptions {
178
+ minLength?: number;
179
+ maxLength?: number;
180
+ default?: string;
181
+ }
182
+ interface JsonOptions extends CommonOptions {
183
+ default?: JsonValue;
184
+ }
185
+ interface AssetOptions extends CommonOptions {
186
+ allowed?: string[];
187
+ multiple?: boolean;
188
+ }
189
+ interface ReferenceOptions extends CommonOptions {
190
+ to: string;
191
+ multiple?: boolean;
192
+ }
193
+ interface SlugOptions extends CommonOptions {
194
+ from?: string;
195
+ }
196
+ interface ListOptions extends CommonOptions {
197
+ of: ListItem;
198
+ minItems?: number;
199
+ maxItems?: number;
200
+ }
201
+ interface ObjectOptions extends CommonOptions {
202
+ fields: Record<string, FieldInput>;
203
+ }
204
+ declare const field: {
205
+ readonly text: (o?: TextOptions) => Omit<TextField, "key">;
206
+ readonly number: (o?: NumberOptions) => Omit<NumberField, "key">;
207
+ readonly boolean: (o?: BooleanOptions) => Omit<BooleanField, "key">;
208
+ readonly date: (o?: DateOptions) => Omit<DateField, "key">;
209
+ readonly datetime: (o?: DateOptions) => Omit<DateField, "key">;
210
+ readonly markdown: (o?: MarkdownOptions) => Omit<MarkdownField, "key">;
211
+ readonly json: (o?: JsonOptions) => Omit<JsonField, "key">;
212
+ readonly asset: (o?: AssetOptions) => Omit<AssetField, "key">;
213
+ readonly reference: (o: ReferenceOptions) => Omit<ReferenceField, "key">;
214
+ readonly slug: (o?: SlugOptions) => Omit<SlugField, "key">;
215
+ readonly list: (o: ListOptions) => Omit<ListField, "key">;
216
+ readonly object: (o: ObjectOptions) => Omit<ObjectField, "key">;
217
+ };
218
+ /** Item builders for `field.list({ of: item.<type>() })`. */
219
+ declare const item: {
220
+ readonly text: (o?: {
221
+ minLength?: number;
222
+ maxLength?: number;
223
+ pattern?: string;
224
+ enum?: string[];
225
+ }) => ListItem;
226
+ readonly number: (o?: {
227
+ integer?: boolean;
228
+ min?: number;
229
+ max?: number;
230
+ }) => ListItem;
231
+ readonly boolean: () => ListItem;
232
+ readonly date: (o?: {
233
+ min?: string;
234
+ max?: string;
235
+ }) => ListItem;
236
+ readonly datetime: (o?: {
237
+ min?: string;
238
+ max?: string;
239
+ }) => ListItem;
240
+ readonly markdown: (o?: {
241
+ minLength?: number;
242
+ maxLength?: number;
243
+ }) => ListItem;
244
+ readonly json: () => ListItem;
245
+ readonly reference: (o: {
246
+ to: string;
247
+ }) => ListItem;
248
+ readonly asset: (o?: {
249
+ allowed?: string[];
250
+ }) => ListItem;
251
+ readonly object: (o: {
252
+ fields: Record<string, FieldInput>;
253
+ }) => ListItem;
254
+ };
255
+ /** Turn a `{ key: FieldInput }` map into an ordered array of `FieldDef`. */
256
+ declare function assignKeys(fields: Record<string, FieldInput>): FieldDef[];
257
+
258
+ interface CollectionInput {
259
+ /** Immutable collection key, e.g. `posts`. */
260
+ name: string;
261
+ label?: string;
262
+ kind?: CollectionKind;
263
+ /** Visibility defaults to `private` and must be explicitly declared `public`. */
264
+ visibility?: Visibility;
265
+ titleField?: string;
266
+ /** Path template such as `/blog/{slug}`. */
267
+ path?: string;
268
+ fields: Record<string, FieldInput>;
269
+ }
270
+ /**
271
+ * Author a collection schema. Returns the canonical `CollectionSchema` with an
272
+ * ordered fields array. Defaults: `kind=collection`, `visibility=private`.
273
+ */
274
+ declare function collection(input: CollectionInput): CollectionSchema;
275
+
276
+ export { type AssetField, type AssetOptions, type BooleanField, type BooleanOptions, type CollectionInput, type CollectionKind, type CollectionSchema, type DateField, type DateOptions, type FieldDef, type FieldInput, type FieldType, type FieldUi, type JsonField, type JsonOptions, type JsonValue, type ListField, type ListItem, type ListOptions, MAX_NESTING_DEPTH, type MarkdownField, type MarkdownOptions, type NumberField, type NumberOptions, type ObjectField, type ObjectOptions, type PrimitiveItem, type ReferenceField, type ReferenceOptions, type SlugConfig, type SlugField, type SlugOptions, type TextField, type TextOptions, type Visibility, assignKeys, collection, field, item };
package/dist/dsl.js ADDED
@@ -0,0 +1,189 @@
1
+ // ../schema/src/types.ts
2
+ var MAX_NESTING_DEPTH = 4;
3
+
4
+ // ../schema/src/fields.ts
5
+ function common(o) {
6
+ const base = {
7
+ required: o.required ?? false
8
+ };
9
+ if (o.label !== void 0) base.label = o.label;
10
+ if (o.description !== void 0) base.description = o.description;
11
+ if (o.ui !== void 0) base.ui = o.ui;
12
+ return base;
13
+ }
14
+ function defined(obj) {
15
+ for (const key of Object.keys(obj)) {
16
+ if (obj[key] === void 0) delete obj[key];
17
+ }
18
+ return obj;
19
+ }
20
+ var field = {
21
+ text(o = {}) {
22
+ return defined({
23
+ type: "text",
24
+ ...common(o),
25
+ multiline: o.multiline ?? false,
26
+ minLength: o.minLength,
27
+ maxLength: o.maxLength,
28
+ pattern: o.pattern,
29
+ enum: o.enum,
30
+ default: o.default
31
+ });
32
+ },
33
+ number(o = {}) {
34
+ return defined({
35
+ type: "number",
36
+ ...common(o),
37
+ integer: o.integer ?? false,
38
+ min: o.min,
39
+ max: o.max,
40
+ default: o.default
41
+ });
42
+ },
43
+ boolean(o = {}) {
44
+ return defined({
45
+ type: "boolean",
46
+ ...common(o),
47
+ default: o.default
48
+ });
49
+ },
50
+ date(o = {}) {
51
+ return defined({
52
+ type: "date",
53
+ ...common(o),
54
+ min: o.min,
55
+ max: o.max,
56
+ default: o.default
57
+ });
58
+ },
59
+ datetime(o = {}) {
60
+ return defined({
61
+ type: "datetime",
62
+ ...common(o),
63
+ min: o.min,
64
+ max: o.max,
65
+ default: o.default
66
+ });
67
+ },
68
+ markdown(o = {}) {
69
+ return defined({
70
+ type: "markdown",
71
+ ...common(o),
72
+ minLength: o.minLength,
73
+ maxLength: o.maxLength,
74
+ default: o.default
75
+ });
76
+ },
77
+ json(o = {}) {
78
+ return defined({
79
+ type: "json",
80
+ ...common(o),
81
+ default: o.default
82
+ });
83
+ },
84
+ asset(o = {}) {
85
+ return defined({
86
+ type: "asset",
87
+ ...common(o),
88
+ allowed: o.allowed ?? ["*/*"],
89
+ multiple: o.multiple ?? false
90
+ });
91
+ },
92
+ reference(o) {
93
+ return defined({
94
+ type: "reference",
95
+ ...common(o),
96
+ target: o.to,
97
+ multiple: o.multiple ?? false
98
+ });
99
+ },
100
+ slug(o = {}) {
101
+ return defined({
102
+ type: "slug",
103
+ ...common(o),
104
+ from: o.from
105
+ });
106
+ },
107
+ list(o) {
108
+ return defined({
109
+ type: "list",
110
+ ...common(o),
111
+ item: o.of,
112
+ minItems: o.minItems,
113
+ maxItems: o.maxItems
114
+ });
115
+ },
116
+ object(o) {
117
+ return defined({
118
+ type: "object",
119
+ ...common(o),
120
+ fields: assignKeys(o.fields)
121
+ });
122
+ }
123
+ };
124
+ var item = {
125
+ text(o = {}) {
126
+ return defined({ kind: "text", ...o });
127
+ },
128
+ number(o = {}) {
129
+ return defined({ kind: "number", ...o });
130
+ },
131
+ boolean() {
132
+ return { kind: "boolean" };
133
+ },
134
+ date(o = {}) {
135
+ return defined({ kind: "date", ...o });
136
+ },
137
+ datetime(o = {}) {
138
+ return defined({ kind: "datetime", ...o });
139
+ },
140
+ markdown(o = {}) {
141
+ return defined({ kind: "markdown", ...o });
142
+ },
143
+ json() {
144
+ return { kind: "json" };
145
+ },
146
+ reference(o) {
147
+ return { kind: "reference", target: o.to };
148
+ },
149
+ asset(o = {}) {
150
+ return { kind: "asset", allowed: o.allowed ?? ["*/*"] };
151
+ },
152
+ object(o) {
153
+ return { kind: "object", fields: assignKeys(o.fields) };
154
+ }
155
+ };
156
+ function assignKeys(fields) {
157
+ return Object.entries(fields).map(([key, def]) => ({ key, ...def }));
158
+ }
159
+
160
+ // ../schema/src/collection.ts
161
+ function collection(input) {
162
+ const fields = assignKeys(input.fields);
163
+ const slugField = fields.find((f) => f.type === "slug");
164
+ let slug = null;
165
+ if (slugField && slugField.type === "slug") {
166
+ slug = {
167
+ from: slugField.from ?? input.titleField ?? slugField.key,
168
+ required: slugField.required
169
+ };
170
+ }
171
+ return {
172
+ name: input.name,
173
+ label: input.label ?? input.name,
174
+ kind: input.kind ?? "collection",
175
+ visibility: input.visibility ?? "private",
176
+ titleField: input.titleField ?? null,
177
+ slug,
178
+ path: input.path ?? null,
179
+ fields
180
+ };
181
+ }
182
+ export {
183
+ MAX_NESTING_DEPTH,
184
+ assignKeys,
185
+ collection,
186
+ field,
187
+ item
188
+ };
189
+ //# sourceMappingURL=dsl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../schema/src/types.ts","../../schema/src/fields.ts","../../schema/src/collection.ts"],"sourcesContent":["/**\n * Canonical schema representation (SPEC 6.2 / 7).\n *\n * These are the normalized, serializable shapes stored as `schema_json`. Field\n * order is significant and preserved as an array; object *keys* are sorted only\n * during canonical stringification for a stable hash.\n */\n\nexport type FieldType =\n | \"text\"\n | \"number\"\n | \"boolean\"\n | \"date\"\n | \"datetime\"\n | \"markdown\"\n | \"json\"\n | \"asset\"\n | \"reference\"\n | \"list\"\n | \"object\"\n | \"slug\";\n\nexport type JsonValue =\n | string\n | number\n | boolean\n | null\n | JsonValue[]\n | { [key: string]: JsonValue };\n\n/** UI metadata carried on every field (non-semantic, does not affect validation). */\nexport interface FieldUi {\n widget?: string;\n placeholder?: string;\n helpText?: string;\n group?: string;\n hidden?: boolean;\n}\n\ninterface FieldBase {\n key: string;\n type: FieldType;\n label: string;\n description?: string;\n required: boolean;\n ui?: FieldUi;\n}\n\nexport interface TextField extends FieldBase {\n type: \"text\";\n multiline: boolean;\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n enum?: string[];\n default?: string;\n}\n\nexport interface NumberField extends FieldBase {\n type: \"number\";\n integer: boolean;\n min?: number;\n max?: number;\n default?: number;\n}\n\nexport interface BooleanField extends FieldBase {\n type: \"boolean\";\n default?: boolean;\n}\n\nexport interface DateField extends FieldBase {\n type: \"date\" | \"datetime\";\n min?: string;\n max?: string;\n default?: string;\n}\n\nexport interface MarkdownField extends FieldBase {\n type: \"markdown\";\n minLength?: number;\n maxLength?: number;\n default?: string;\n}\n\nexport interface JsonField extends FieldBase {\n type: \"json\";\n default?: JsonValue;\n}\n\nexport interface AssetField extends FieldBase {\n type: \"asset\";\n /** Allowed MIME families, e.g. `image/*`, `application/pdf`. */\n allowed: string[];\n multiple: boolean;\n}\n\nexport interface ReferenceField extends FieldBase {\n type: \"reference\";\n /** Target collection key. */\n target: string;\n multiple: boolean;\n}\n\nexport interface SlugField extends FieldBase {\n type: \"slug\";\n /** Source field key to derive the slug from. */\n from?: string;\n}\n\nexport type PrimitiveItem =\n | { kind: \"text\"; minLength?: number; maxLength?: number; pattern?: string; enum?: string[] }\n | { kind: \"number\"; integer?: boolean; min?: number; max?: number }\n | { kind: \"boolean\" }\n | { kind: \"date\" | \"datetime\"; min?: string; max?: string }\n | { kind: \"markdown\"; minLength?: number; maxLength?: number }\n | { kind: \"json\" };\n\nexport type ListItem =\n | PrimitiveItem\n | { kind: \"reference\"; target: string }\n | { kind: \"asset\"; allowed: string[] }\n | { kind: \"object\"; fields: FieldDef[] };\n\nexport interface ListField extends FieldBase {\n type: \"list\";\n item: ListItem;\n minItems?: number;\n maxItems?: number;\n}\n\nexport interface ObjectField extends FieldBase {\n type: \"object\";\n fields: FieldDef[];\n}\n\nexport type FieldDef =\n | TextField\n | NumberField\n | BooleanField\n | DateField\n | MarkdownField\n | JsonField\n | AssetField\n | ReferenceField\n | SlugField\n | ListField\n | ObjectField;\n\nexport type CollectionKind = \"collection\" | \"singleton\";\nexport type Visibility = \"public\" | \"private\";\n\nexport interface SlugConfig {\n from: string;\n required: boolean;\n}\n\n/** Canonical collection schema (one `collection_versions.schema_json`). */\nexport interface CollectionSchema {\n name: string;\n label: string;\n kind: CollectionKind;\n visibility: Visibility;\n titleField: string | null;\n slug: SlugConfig | null;\n path: string | null;\n fields: FieldDef[];\n}\n\n/** Maximum object/list nesting depth (SPEC 6.2). */\nexport const MAX_NESTING_DEPTH = 4;\n","import type {\n AssetField,\n BooleanField,\n DateField,\n FieldDef,\n FieldUi,\n JsonField,\n JsonValue,\n ListField,\n ListItem,\n MarkdownField,\n NumberField,\n ObjectField,\n ReferenceField,\n SlugField,\n TextField,\n} from \"./types.js\";\n\n/** A field definition before its `key` is assigned by `collection()`. */\nexport type FieldInput = DistributiveOmit<FieldDef, \"key\">;\n\ntype DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;\n\ninterface CommonOptions {\n label?: string;\n description?: string;\n required?: boolean;\n ui?: FieldUi;\n}\n\nfunction common(o: CommonOptions): { label?: string; description?: string; required: boolean; ui?: FieldUi } {\n const base: { label?: string; description?: string; required: boolean; ui?: FieldUi } = {\n required: o.required ?? false,\n };\n if (o.label !== undefined) base.label = o.label;\n if (o.description !== undefined) base.description = o.description;\n if (o.ui !== undefined) base.ui = o.ui;\n return base;\n}\n\nexport interface TextOptions extends CommonOptions {\n multiline?: boolean;\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n enum?: string[];\n default?: string;\n}\nexport interface NumberOptions extends CommonOptions {\n integer?: boolean;\n min?: number;\n max?: number;\n default?: number;\n}\nexport interface BooleanOptions extends CommonOptions {\n default?: boolean;\n}\nexport interface DateOptions extends CommonOptions {\n min?: string;\n max?: string;\n default?: string;\n}\nexport interface MarkdownOptions extends CommonOptions {\n minLength?: number;\n maxLength?: number;\n default?: string;\n}\nexport interface JsonOptions extends CommonOptions {\n default?: JsonValue;\n}\nexport interface AssetOptions extends CommonOptions {\n allowed?: string[];\n multiple?: boolean;\n}\nexport interface ReferenceOptions extends CommonOptions {\n to: string;\n multiple?: boolean;\n}\nexport interface SlugOptions extends CommonOptions {\n from?: string;\n}\nexport interface ListOptions extends CommonOptions {\n of: ListItem;\n minItems?: number;\n maxItems?: number;\n}\nexport interface ObjectOptions extends CommonOptions {\n fields: Record<string, FieldInput>;\n}\n\nfunction defined<T extends Record<string, unknown>>(obj: T): T {\n for (const key of Object.keys(obj)) {\n if (obj[key] === undefined) delete obj[key];\n }\n return obj;\n}\n\nexport const field = {\n text(o: TextOptions = {}): Omit<TextField, \"key\"> {\n return defined({\n type: \"text\",\n ...common(o),\n multiline: o.multiline ?? false,\n minLength: o.minLength,\n maxLength: o.maxLength,\n pattern: o.pattern,\n enum: o.enum,\n default: o.default,\n }) as Omit<TextField, \"key\">;\n },\n\n number(o: NumberOptions = {}): Omit<NumberField, \"key\"> {\n return defined({\n type: \"number\",\n ...common(o),\n integer: o.integer ?? false,\n min: o.min,\n max: o.max,\n default: o.default,\n }) as Omit<NumberField, \"key\">;\n },\n\n boolean(o: BooleanOptions = {}): Omit<BooleanField, \"key\"> {\n return defined({\n type: \"boolean\",\n ...common(o),\n default: o.default,\n }) as Omit<BooleanField, \"key\">;\n },\n\n date(o: DateOptions = {}): Omit<DateField, \"key\"> {\n return defined({\n type: \"date\",\n ...common(o),\n min: o.min,\n max: o.max,\n default: o.default,\n }) as Omit<DateField, \"key\">;\n },\n\n datetime(o: DateOptions = {}): Omit<DateField, \"key\"> {\n return defined({\n type: \"datetime\",\n ...common(o),\n min: o.min,\n max: o.max,\n default: o.default,\n }) as Omit<DateField, \"key\">;\n },\n\n markdown(o: MarkdownOptions = {}): Omit<MarkdownField, \"key\"> {\n return defined({\n type: \"markdown\",\n ...common(o),\n minLength: o.minLength,\n maxLength: o.maxLength,\n default: o.default,\n }) as Omit<MarkdownField, \"key\">;\n },\n\n json(o: JsonOptions = {}): Omit<JsonField, \"key\"> {\n return defined({\n type: \"json\",\n ...common(o),\n default: o.default,\n }) as Omit<JsonField, \"key\">;\n },\n\n asset(o: AssetOptions = {}): Omit<AssetField, \"key\"> {\n return defined({\n type: \"asset\",\n ...common(o),\n allowed: o.allowed ?? [\"*/*\"],\n multiple: o.multiple ?? false,\n }) as Omit<AssetField, \"key\">;\n },\n\n reference(o: ReferenceOptions): Omit<ReferenceField, \"key\"> {\n return defined({\n type: \"reference\",\n ...common(o),\n target: o.to,\n multiple: o.multiple ?? false,\n }) as Omit<ReferenceField, \"key\">;\n },\n\n slug(o: SlugOptions = {}): Omit<SlugField, \"key\"> {\n return defined({\n type: \"slug\",\n ...common(o),\n from: o.from,\n }) as Omit<SlugField, \"key\">;\n },\n\n list(o: ListOptions): Omit<ListField, \"key\"> {\n return defined({\n type: \"list\",\n ...common(o),\n item: o.of,\n minItems: o.minItems,\n maxItems: o.maxItems,\n }) as Omit<ListField, \"key\">;\n },\n\n object(o: ObjectOptions): Omit<ObjectField, \"key\"> {\n return defined({\n type: \"object\",\n ...common(o),\n fields: assignKeys(o.fields),\n }) as Omit<ObjectField, \"key\">;\n },\n} as const;\n\n/** Item builders for `field.list({ of: item.<type>() })`. */\nexport const item = {\n text(o: { minLength?: number; maxLength?: number; pattern?: string; enum?: string[] } = {}): ListItem {\n return defined({ kind: \"text\", ...o }) as ListItem;\n },\n number(o: { integer?: boolean; min?: number; max?: number } = {}): ListItem {\n return defined({ kind: \"number\", ...o }) as ListItem;\n },\n boolean(): ListItem {\n return { kind: \"boolean\" };\n },\n date(o: { min?: string; max?: string } = {}): ListItem {\n return defined({ kind: \"date\", ...o }) as ListItem;\n },\n datetime(o: { min?: string; max?: string } = {}): ListItem {\n return defined({ kind: \"datetime\", ...o }) as ListItem;\n },\n markdown(o: { minLength?: number; maxLength?: number } = {}): ListItem {\n return defined({ kind: \"markdown\", ...o }) as ListItem;\n },\n json(): ListItem {\n return { kind: \"json\" };\n },\n reference(o: { to: string }): ListItem {\n return { kind: \"reference\", target: o.to };\n },\n asset(o: { allowed?: string[] } = {}): ListItem {\n return { kind: \"asset\", allowed: o.allowed ?? [\"*/*\"] };\n },\n object(o: { fields: Record<string, FieldInput> }): ListItem {\n return { kind: \"object\", fields: assignKeys(o.fields) };\n },\n} as const;\n\n/** Turn a `{ key: FieldInput }` map into an ordered array of `FieldDef`. */\nexport function assignKeys(fields: Record<string, FieldInput>): FieldDef[] {\n return Object.entries(fields).map(([key, def]) => ({ key, ...def }) as FieldDef);\n}\n","import { assignKeys, type FieldInput } from \"./fields.js\";\nimport type { CollectionKind, CollectionSchema, SlugConfig, Visibility } from \"./types.js\";\n\nexport interface CollectionInput {\n /** Immutable collection key, e.g. `posts`. */\n name: string;\n label?: string;\n kind?: CollectionKind;\n /** Visibility defaults to `private` and must be explicitly declared `public`. */\n visibility?: Visibility;\n titleField?: string;\n /** Path template such as `/blog/{slug}`. */\n path?: string;\n fields: Record<string, FieldInput>;\n}\n\n/**\n * Author a collection schema. Returns the canonical `CollectionSchema` with an\n * ordered fields array. Defaults: `kind=collection`, `visibility=private`.\n */\nexport function collection(input: CollectionInput): CollectionSchema {\n const fields = assignKeys(input.fields);\n const slugField = fields.find((f) => f.type === \"slug\");\n\n let slug: SlugConfig | null = null;\n if (slugField && slugField.type === \"slug\") {\n slug = {\n from: slugField.from ?? input.titleField ?? slugField.key,\n required: slugField.required,\n };\n }\n\n return {\n name: input.name,\n label: input.label ?? input.name,\n kind: input.kind ?? \"collection\",\n visibility: input.visibility ?? \"private\",\n titleField: input.titleField ?? null,\n slug,\n path: input.path ?? null,\n fields,\n };\n}\n"],"mappings":"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","names":[]}
package/dist/main.js CHANGED
@@ -945,9 +945,14 @@ function registerAuth(program) {
945
945
  handle(async (ctx) => {
946
946
  const token = ctx.token ?? loadToken(ctx.apiUrl);
947
947
  if (!token) throw new CliError("Not authenticated. Run `myna login`.");
948
- const account = await fetch(`${ctx.apiUrl}/v1/account`, {
948
+ const identityResponse = await fetch(`${ctx.apiUrl}/v1/auth/whoami`, {
949
949
  headers: { authorization: `Bearer ${token}`, accept: "application/json" }
950
- }).then(async (r) => r.ok ? (await r.json()).data.user : void 0).catch(() => void 0);
950
+ });
951
+ const identityBody = await identityResponse.json().catch(() => ({}));
952
+ if (!identityResponse.ok || !identityBody.data) {
953
+ throw new CliError(identityBody.detail ?? "Stored credential is invalid. Run `myna login` again.");
954
+ }
955
+ const identity = identityBody.data;
951
956
  let organization;
952
957
  if (ctx.organization) {
953
958
  organization = await ctx.management().organizations.get(ctx.organization).then((o) => ({ name: o.name, role: o.role, slug: o.slug })).catch((e) => {
@@ -955,12 +960,12 @@ function registerAuth(program) {
955
960
  throw e;
956
961
  });
957
962
  }
958
- emit({ apiUrl: ctx.apiUrl, authenticated: true, account: account ?? null, organization: organization ?? null }, () => {
963
+ emit({ apiUrl: ctx.apiUrl, authenticated: true, identity, organization: organization ?? null }, () => {
959
964
  const pairs = [["API", ctx.apiUrl], ["Authenticated", "yes"]];
960
- if (account && typeof account === "object" && "username" in account) {
961
- pairs.push(["User", String(account.username)]);
965
+ if (identity.credential === "user") {
966
+ pairs.push(["User", identity.user?.username ?? "(unknown)"]);
962
967
  } else {
963
- pairs.push(["Credential", "API token"]);
968
+ pairs.push(["Credential", identity.credential === "api_key" ? "API key" : "Preview token"]);
964
969
  }
965
970
  if (organization) pairs.push(["Organization", `${organization.name} (${organization.role})`]);
966
971
  keyValues(pairs);
@@ -972,7 +977,7 @@ function registerAuth(program) {
972
977
  // src/commands/workspace.ts
973
978
  import { existsSync as existsSync2, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
974
979
  import { join as join2 } from "path";
975
- var EXAMPLE_SCHEMA = `import { collection, field } from "@myna-sh/schema";
980
+ var EXAMPLE_SCHEMA = `import { collection, field } from "@myna-sh/sdk/schema";
976
981
 
977
982
  /**
978
983
  * Example collection. Edit freely, then run:
@@ -1103,6 +1108,7 @@ import { join as join4 } from "path";
1103
1108
  // src/schema-loader.ts
1104
1109
  import { existsSync as existsSync3, readdirSync, statSync } from "fs";
1105
1110
  import { join as join3, resolve as resolve2 } from "path";
1111
+ import { fileURLToPath } from "url";
1106
1112
  import { build } from "esbuild";
1107
1113
 
1108
1114
  // ../schema/dist/canonical.js
@@ -1130,6 +1136,18 @@ function toCanonical(schema) {
1130
1136
 
1131
1137
  // src/schema-loader.ts
1132
1138
  var DEFAULT_SCHEMA_DIR = "myna";
1139
+ function dslAliasPlugin() {
1140
+ let dslPath = fileURLToPath(new URL("./dsl.js", import.meta.url));
1141
+ if (!existsSync3(dslPath)) dslPath = dslPath.replace(/\.js$/, ".ts");
1142
+ return {
1143
+ name: "myna-dsl-alias",
1144
+ setup(builder) {
1145
+ builder.onResolve({ filter: /^@myna-sh\/(schema|sdk\/schema)$/ }, () => ({
1146
+ path: dslPath
1147
+ }));
1148
+ }
1149
+ };
1150
+ }
1133
1151
  function looksLikeCollection(value) {
1134
1152
  return typeof value === "object" && value !== null && typeof value.name === "string" && Array.isArray(value.fields);
1135
1153
  }
@@ -1176,7 +1194,8 @@ async function loadLocalSchemas(schemaDir = DEFAULT_SCHEMA_DIR) {
1176
1194
  platform: "node",
1177
1195
  target: "node20",
1178
1196
  logLevel: "silent",
1179
- absWorkingDir: process.cwd()
1197
+ absWorkingDir: process.cwd(),
1198
+ plugins: [dslAliasPlugin()]
1180
1199
  }).catch((error) => {
1181
1200
  throw new CliError(`Failed to compile ${file}: ${error instanceof Error ? error.message : String(error)}`);
1182
1201
  });
@@ -1214,7 +1233,7 @@ function schemaToDsl(schema) {
1214
1233
  if (schema.path) opts.push(`path: ${str(schema.path)}`);
1215
1234
  const fieldLines = schema.fields.map((f) => ` ${ident(f.key)}: ${emitField(f)},`).join("\n");
1216
1235
  return [
1217
- `import { collection, field, item } from "@myna-sh/schema";`,
1236
+ `import { collection, field, item } from "@myna-sh/sdk/schema";`,
1218
1237
  ``,
1219
1238
  `export const ${varName(schema.name)} = collection({`,
1220
1239
  ` ${opts.join(",\n ")},`,
@@ -2116,7 +2135,7 @@ function registerBilling(program) {
2116
2135
  }
2117
2136
 
2118
2137
  // src/main.ts
2119
- var VERSION = "0.1.0";
2138
+ var VERSION = "0.1.3";
2120
2139
  var GLOBAL_VALUE_FLAGS = /* @__PURE__ */ new Set(["--project", "--organization", "--token", "--api-url"]);
2121
2140
  var GLOBAL_BOOL_FLAGS = /* @__PURE__ */ new Set(["--json", "--no-interactive", "--interactive"]);
2122
2141
  function normalizeGlobals(argv) {