attio 0.0.1-experimental.20250218 → 0.0.1-experimental.20250227

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.
@@ -1,409 +0,0 @@
1
- import { existsSync } from "fs";
2
- import Spinner from "tiny-spinner";
3
- import path, { join } from "path";
4
- import { fileURLToPath } from "url";
5
- import { assign, setup, fromCallback } from "xstate";
6
- import { createApp } from "../api/create-app.js";
7
- import { isAppSlugValid } from "../api/is-app-slug-valid.js";
8
- import { copyWithTransform } from "../util/copy-with-replace.js";
9
- import { createDirectory } from "../util/create-directory.js";
10
- import { loadDeveloperConfig } from "../util/load-developer-config.js";
11
- import { slugifyExtension } from "../util/slugify-extension.js";
12
- import { canWrite, isValidSlug } from "../util/validate-slug.js";
13
- import { ask, askWithChoices } from "./actors.js";
14
- import { showError, printLogo } from "./actions.js";
15
- import chalk from "chalk";
16
- import boxen from "boxen";
17
- import { printInstallInstructions } from "../util/print-install-instructions.js";
18
- export const languages = [
19
- { name: "TypeScript – recommended!", value: "typescript" },
20
- { name: "JavaScript", value: "javascript" },
21
- ];
22
- export const createMachine = setup({
23
- types: {
24
- context: {},
25
- events: {},
26
- input: {},
27
- },
28
- actors: {
29
- ask,
30
- askWithChoices,
31
- createProject: fromCallback(({ sendBack, input }) => {
32
- const create = async () => {
33
- try {
34
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
35
- const projectDir = createDirectory(input.appSlug);
36
- const templatesDir = path.resolve(__dirname, "../templates", input.language);
37
- const commonDir = path.resolve(__dirname, "../templates", "common");
38
- const transform = (contents) => contents
39
- .replaceAll("title-to-be-replaced", input.title)
40
- .replaceAll("id-to-be-replaced", input.appId)
41
- .replaceAll("slug-to-be-replaced", input.appSlug);
42
- await Promise.all([
43
- copyWithTransform(templatesDir, projectDir, transform),
44
- copyWithTransform(commonDir, projectDir, transform),
45
- ]);
46
- sendBack({ type: "Success" });
47
- }
48
- catch (error) {
49
- sendBack({ type: "Error", error: error.message });
50
- }
51
- };
52
- create();
53
- }),
54
- createApp: fromCallback(({ sendBack, input: { appSlug, token, developerSlug, title } }) => {
55
- const create = async () => {
56
- const spinner = new Spinner();
57
- spinner.start(`Creating app "${title}"...`);
58
- try {
59
- const result = await createApp({
60
- token,
61
- developerSlug,
62
- appSlug: appSlug,
63
- title,
64
- });
65
- spinner.success(`"${title}" created!`);
66
- sendBack({ type: "App Created", appId: result.app_id });
67
- }
68
- catch (error) {
69
- spinner.error(error.message);
70
- sendBack({ type: "Error", error: error.message });
71
- }
72
- };
73
- create();
74
- }),
75
- loadConfig: fromCallback(({ sendBack }) => {
76
- const load = async () => {
77
- const config = await loadDeveloperConfig();
78
- if (typeof config === "string") {
79
- sendBack({ type: "No Config", configError: config });
80
- return;
81
- }
82
- sendBack({
83
- type: "Config Loaded",
84
- token: config.token,
85
- developerSlug: config.developer_slug,
86
- });
87
- };
88
- load();
89
- }),
90
- validateSlug: fromCallback(({ sendBack, input: { appSlug, token, developerSlug } }) => {
91
- const spinner = new Spinner();
92
- spinner.start("Checking if slug is valid...");
93
- if (!isValidSlug(appSlug)) {
94
- spinner.error("Invalid slug");
95
- sendBack({
96
- type: "Invalid Slug",
97
- error: "Slug contains invalid characters. Must be lowercase letters or hyphens only.",
98
- });
99
- }
100
- if (existsSync(join(process.cwd(), appSlug))) {
101
- spinner.error("Invalid slug");
102
- sendBack({
103
- type: "Invalid Slug",
104
- error: `Directory "${appSlug}" already exists`,
105
- });
106
- return;
107
- }
108
- if (!canWrite(".")) {
109
- spinner.error("Fatal Error");
110
- sendBack({
111
- type: "Fatal Error",
112
- error: "Write access denied to current directory",
113
- });
114
- return;
115
- }
116
- isAppSlugValid({ token, developerSlug, appSlug: appSlug })
117
- .then((valid) => {
118
- spinner.success("Valid slug");
119
- sendBack(valid
120
- ? { type: "Valid Slug" }
121
- : {
122
- type: "Invalid Slug",
123
- error: "An app already exists with this slug",
124
- });
125
- })
126
- .catch((error) => {
127
- spinner.error("Fatal Error");
128
- sendBack({ type: "Fatal Error", error: error.message });
129
- });
130
- }),
131
- },
132
- actions: {
133
- printLogo,
134
- clearError: assign({
135
- error: () => undefined,
136
- }),
137
- showError,
138
- showConfigInstructions: ({ context: { configError } }) => {
139
- printInstallInstructions(configError);
140
- },
141
- showInstructions: ({ context: { appSlug, title } }) => {
142
- const commands = `cd ${appSlug}\nnpm install\nnpm run dev`;
143
- process.stdout.write("\n" +
144
- chalk.green(`SUCCESS!! 🎉 Your extension "${title}" has been created.`) +
145
- "\n");
146
- process.stdout.write("\nTo get started, run:\n");
147
- process.stdout.write(boxen(commands, {
148
- padding: 1,
149
- margin: 1,
150
- borderStyle: "round",
151
- }) + "\n");
152
- process.stdout.write(`(${chalk.yellow("yarn")}, ${chalk.yellow("pnpm")}, and ${chalk.yellow("bun")} also work!)\n`);
153
- },
154
- setLanguage: assign({
155
- language: (_, params) => params.output,
156
- }),
157
- setTitle: assign({
158
- title: (_, params) => params.output,
159
- }),
160
- setConfig: assign({
161
- token: (_, params) => params.token,
162
- developerSlug: (_, params) => params.developerSlug,
163
- }),
164
- setConfigError: assign({
165
- configError: (_, params) => params.configError,
166
- }),
167
- setAppId: assign({
168
- appId: (_, params) => params.appId,
169
- }),
170
- setSlug: assign({
171
- appSlug: (_, params) => slugifyExtension(params.output, false),
172
- }),
173
- slugifyTitle: assign({
174
- appSlug: (_, params) => slugifyExtension(params.title),
175
- }),
176
- },
177
- guards: {
178
- "have title": (_, params) => Boolean(params.title.trim()),
179
- "have slug": (_, params) => Boolean(params.slug.trim()),
180
- "have language": (_, params) => Boolean(params.language),
181
- },
182
- }).createMachine({
183
- context: ({ input }) => ({
184
- availablePackageManagers: ["npm"],
185
- developerSlug: "",
186
- appId: "",
187
- appSlug: "",
188
- token: "",
189
- ...input,
190
- }),
191
- id: "Create Machine",
192
- states: {
193
- "Do we need title?": {
194
- always: [
195
- {
196
- target: "Validate Slug From CLI Title",
197
- guard: { type: "have title", params: ({ context }) => context },
198
- description: `Title may have been provided via CLI arg`,
199
- actions: { type: "slugifyTitle", params: ({ context }) => context },
200
- reenter: true,
201
- },
202
- {
203
- target: "Ask for title",
204
- reenter: true,
205
- },
206
- ],
207
- },
208
- "Ask for title": {
209
- invoke: {
210
- src: "ask",
211
- input: {
212
- message: 'What would you like to call your new app? (in "Title Case")',
213
- required: true,
214
- },
215
- onDone: {
216
- target: "Validate Slug From Title",
217
- actions: [
218
- { type: "setTitle", params: ({ event }) => event },
219
- { type: "slugifyTitle", params: ({ context }) => context },
220
- ],
221
- },
222
- },
223
- },
224
- "Ask for language": {
225
- invoke: {
226
- src: "askWithChoices",
227
- input: {
228
- message: "What language would you like to use?",
229
- choices: languages,
230
- },
231
- onDone: {
232
- target: "Create App",
233
- actions: {
234
- type: "setLanguage",
235
- params: ({ event }) => event,
236
- },
237
- reenter: true,
238
- },
239
- },
240
- },
241
- "Creating Project": {
242
- on: {
243
- Error: {
244
- target: "Error",
245
- actions: { type: "showError", params: ({ event }) => event },
246
- },
247
- Success: {
248
- target: "Success",
249
- reenter: true,
250
- },
251
- },
252
- invoke: {
253
- src: "createProject",
254
- input: ({ context }) => ({
255
- title: context.title,
256
- language: context.language,
257
- appId: context.appId,
258
- appSlug: context.appSlug,
259
- }),
260
- },
261
- },
262
- "Error": {
263
- type: "final",
264
- description: `😭😭😭😭😭`,
265
- },
266
- "Success": {
267
- type: "final",
268
- description: `🎉🎉🎉🎉🎉🎉`,
269
- entry: "showInstructions",
270
- },
271
- "Do we need language?": {
272
- always: [
273
- {
274
- target: "Create App",
275
- guard: { type: "have language", params: ({ context }) => context },
276
- reenter: true,
277
- description: `language may have been provided by CLI option`,
278
- },
279
- "Ask for language",
280
- ],
281
- },
282
- "Validate Slug": {
283
- invoke: [
284
- {
285
- src: "validateSlug",
286
- input: ({ context }) => context,
287
- },
288
- ],
289
- on: {
290
- "Invalid Slug": {
291
- target: "Ask for slug",
292
- actions: {
293
- type: "showError",
294
- params: ({ event }) => event,
295
- },
296
- reenter: true,
297
- },
298
- "Valid Slug": {
299
- target: "Do we need language?",
300
- actions: "clearError",
301
- },
302
- },
303
- description: `Checks if can create directory and if app with this slug already exists on backend`,
304
- },
305
- "Load Config": {
306
- on: {
307
- "No Config": {
308
- target: "Show config instructions",
309
- actions: { type: "setConfigError", params: ({ event }) => event },
310
- },
311
- "Config Loaded": {
312
- target: "Do we need title?",
313
- actions: { type: "setConfig", params: ({ event }) => event },
314
- },
315
- },
316
- invoke: {
317
- src: "loadConfig",
318
- },
319
- },
320
- "Show config instructions": {
321
- type: "final",
322
- entry: "showConfigInstructions",
323
- },
324
- "Create App": {
325
- invoke: {
326
- src: "createApp",
327
- input: ({ context }) => context,
328
- },
329
- on: {
330
- "App Created": {
331
- target: "Creating Project",
332
- actions: { type: "setAppId", params: ({ event }) => event },
333
- },
334
- "Error": {
335
- target: "Error",
336
- actions: { type: "showError", params: ({ event }) => event },
337
- },
338
- },
339
- },
340
- "Ask for slug": {
341
- invoke: {
342
- src: "ask",
343
- input: ({ context }) => ({
344
- message: "Please provide a slug for your extension:",
345
- default: context.appSlug,
346
- required: true,
347
- }),
348
- onDone: {
349
- target: "Validate Slug",
350
- actions: { type: "setSlug", params: ({ event }) => event },
351
- },
352
- },
353
- },
354
- "Validate Slug From Title": {
355
- invoke: {
356
- src: "validateSlug",
357
- input: ({ context }) => context,
358
- },
359
- on: {
360
- "Invalid Slug": {
361
- target: "Ask for slug",
362
- actions: {
363
- type: "showError",
364
- params: ({ event }) => event,
365
- },
366
- },
367
- "Valid Slug": {
368
- target: "Ask for slug",
369
- description: `Just double check with user that they like their slug`,
370
- },
371
- "Fatal Error": {
372
- target: "Error",
373
- actions: {
374
- type: "showError",
375
- params: ({ event }) => event,
376
- },
377
- },
378
- },
379
- },
380
- "Validate Slug From CLI Title": {
381
- invoke: {
382
- src: "validateSlug",
383
- input: ({ context }) => context,
384
- },
385
- on: {
386
- "Invalid Slug": {
387
- target: "Ask for slug",
388
- actions: {
389
- type: "showError",
390
- params: ({ event }) => event,
391
- },
392
- },
393
- "Valid Slug": {
394
- target: "Do we need language?",
395
- reenter: true,
396
- },
397
- "Fatal Error": {
398
- target: "Error",
399
- actions: {
400
- type: "showError",
401
- params: ({ event }) => event,
402
- },
403
- },
404
- },
405
- },
406
- },
407
- initial: "Load Config",
408
- entry: "printLogo",
409
- });
@@ -1,14 +0,0 @@
1
- export function slugifyExtension(string, trim = true) {
2
- const slug = (trim ? string.trim() : string)
3
- .toLowerCase()
4
- .replace(/[\s._@]/g, "-")
5
- .replace(/[^\w-]/g, "");
6
- if (trim) {
7
- return slug
8
- .replace(/^-+|-+$/g, "")
9
- .replace(/--+/g, "-");
10
- }
11
- return slug
12
- .replace(/^-+/g, "")
13
- .replace(/(?!-+$)--+/g, "-");
14
- }