@specific.dev/cli 0.1.123 → 0.1.125

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/dist/admin/404/index.html +1 -1
  2. package/dist/admin/404.html +1 -1
  3. package/dist/admin/__next.!KGRlZmF1bHQp.__PAGE__.txt +1 -1
  4. package/dist/admin/__next.!KGRlZmF1bHQp.txt +1 -1
  5. package/dist/admin/__next._full.txt +1 -1
  6. package/dist/admin/__next._head.txt +1 -1
  7. package/dist/admin/__next._index.txt +1 -1
  8. package/dist/admin/__next._tree.txt +1 -1
  9. package/dist/admin/_not-found/__next._full.txt +1 -1
  10. package/dist/admin/_not-found/__next._head.txt +1 -1
  11. package/dist/admin/_not-found/__next._index.txt +1 -1
  12. package/dist/admin/_not-found/__next._not-found.__PAGE__.txt +1 -1
  13. package/dist/admin/_not-found/__next._not-found.txt +1 -1
  14. package/dist/admin/_not-found/__next._tree.txt +1 -1
  15. package/dist/admin/_not-found/index.html +1 -1
  16. package/dist/admin/_not-found/index.txt +1 -1
  17. package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.__PAGE__.txt +1 -1
  18. package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.txt +1 -1
  19. package/dist/admin/databases/__next.!KGRlZmF1bHQp.txt +1 -1
  20. package/dist/admin/databases/__next._full.txt +1 -1
  21. package/dist/admin/databases/__next._head.txt +1 -1
  22. package/dist/admin/databases/__next._index.txt +1 -1
  23. package/dist/admin/databases/__next._tree.txt +1 -1
  24. package/dist/admin/databases/index.html +1 -1
  25. package/dist/admin/databases/index.txt +1 -1
  26. package/dist/admin/fullscreen/__next._full.txt +1 -1
  27. package/dist/admin/fullscreen/__next._head.txt +1 -1
  28. package/dist/admin/fullscreen/__next._index.txt +1 -1
  29. package/dist/admin/fullscreen/__next._tree.txt +1 -1
  30. package/dist/admin/fullscreen/__next.fullscreen.__PAGE__.txt +1 -1
  31. package/dist/admin/fullscreen/__next.fullscreen.txt +1 -1
  32. package/dist/admin/fullscreen/databases/__next._full.txt +1 -1
  33. package/dist/admin/fullscreen/databases/__next._head.txt +1 -1
  34. package/dist/admin/fullscreen/databases/__next._index.txt +1 -1
  35. package/dist/admin/fullscreen/databases/__next._tree.txt +1 -1
  36. package/dist/admin/fullscreen/databases/__next.fullscreen.databases.__PAGE__.txt +1 -1
  37. package/dist/admin/fullscreen/databases/__next.fullscreen.databases.txt +1 -1
  38. package/dist/admin/fullscreen/databases/__next.fullscreen.txt +1 -1
  39. package/dist/admin/fullscreen/databases/index.html +1 -1
  40. package/dist/admin/fullscreen/databases/index.txt +1 -1
  41. package/dist/admin/fullscreen/index.html +1 -1
  42. package/dist/admin/fullscreen/index.txt +1 -1
  43. package/dist/admin/index.html +1 -1
  44. package/dist/admin/index.txt +1 -1
  45. package/dist/admin/mail/__next.!KGRlZmF1bHQp.mail.__PAGE__.txt +1 -1
  46. package/dist/admin/mail/__next.!KGRlZmF1bHQp.mail.txt +1 -1
  47. package/dist/admin/mail/__next.!KGRlZmF1bHQp.txt +1 -1
  48. package/dist/admin/mail/__next._full.txt +1 -1
  49. package/dist/admin/mail/__next._head.txt +1 -1
  50. package/dist/admin/mail/__next._index.txt +1 -1
  51. package/dist/admin/mail/__next._tree.txt +1 -1
  52. package/dist/admin/mail/index.html +1 -1
  53. package/dist/admin/mail/index.txt +1 -1
  54. package/dist/admin/workflows/__next.!KGRlZmF1bHQp.txt +1 -1
  55. package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.__PAGE__.txt +1 -1
  56. package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.txt +1 -1
  57. package/dist/admin/workflows/__next._full.txt +1 -1
  58. package/dist/admin/workflows/__next._head.txt +1 -1
  59. package/dist/admin/workflows/__next._index.txt +1 -1
  60. package/dist/admin/workflows/__next._tree.txt +1 -1
  61. package/dist/admin/workflows/index.html +1 -1
  62. package/dist/admin/workflows/index.txt +1 -1
  63. package/dist/cli.js +63 -10
  64. package/dist/docs/index.md +1 -3
  65. package/dist/docs/integrations/temporal.md +1 -91
  66. package/dist/docs/postgres.md +1 -0
  67. package/dist/docs/temporal.md +0 -2
  68. package/package.json +1 -1
  69. /package/dist/admin/_next/static/{iKEnJVRd6gOzhr5N6iD4r → r3veCvOuDWyK-S0rsl-XQ}/_buildManifest.js +0 -0
  70. /package/dist/admin/_next/static/{iKEnJVRd6gOzhr5N6iD4r → r3veCvOuDWyK-S0rsl-XQ}/_clientMiddlewareManifest.json +0 -0
  71. /package/dist/admin/_next/static/{iKEnJVRd6gOzhr5N6iD4r → r3veCvOuDWyK-S0rsl-XQ}/_ssgManifest.js +0 -0
package/dist/cli.js CHANGED
@@ -373341,7 +373341,7 @@ function trackEvent(event, properties) {
373341
373341
  event,
373342
373342
  properties: {
373343
373343
  ...properties,
373344
- cli_version: "0.1.123",
373344
+ cli_version: "0.1.125",
373345
373345
  platform: process.platform,
373346
373346
  node_version: process.version,
373347
373347
  project_id: getProjectId()
@@ -373666,10 +373666,6 @@ import { fileURLToPath as fileURLToPath3 } from "url";
373666
373666
 
373667
373667
  // src/lib/beta/registry.ts
373668
373668
  var BETA_REGISTRY = [
373669
- {
373670
- name: "temporal",
373671
- description: "Managed Temporal workflow engine for durable workflows and background tasks"
373672
- },
373673
373669
  {
373674
373670
  name: "mail",
373675
373671
  description: "Managed email sending via SMTP for transactional emails"
@@ -375223,6 +375219,7 @@ function PhaseIndicator({
375223
375219
  showSpinner = true
375224
375220
  }) {
375225
375221
  const phases = [
375222
+ "creating-preview",
375226
375223
  "creating-tarball",
375227
375224
  "creating-deployment",
375228
375225
  "uploading",
@@ -375374,7 +375371,7 @@ function formatErrorCode(code) {
375374
375371
  function StructuredError({ error }) {
375375
375372
  return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Text7, { color: "red", bold: true }, formatErrorCode(error.code), ": ", error.message), error.resource && /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, "Resource: ", error.resource), error.output && /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React7.createElement(Text7, { bold: true }, "Output:"), /* @__PURE__ */ React7.createElement(Text7, null, error.output)));
375376
375373
  }
375377
- function DeployUI({ envFlag, config }) {
375374
+ function DeployUI({ envFlag, preview, config }) {
375378
375375
  const { exit } = useApp3();
375379
375376
  const [state, setState] = useState6({ phase: "checking-auth" });
375380
375377
  const clientRef = React7.useRef(null);
@@ -375562,6 +375559,15 @@ function DeployUI({ envFlag, config }) {
375562
375559
  }));
375563
375560
  return;
375564
375561
  }
375562
+ if (preview) {
375563
+ setState((s) => ({
375564
+ ...s,
375565
+ phase: "creating-preview",
375566
+ environments,
375567
+ previewStatus: "Creating preview environment"
375568
+ }));
375569
+ return;
375570
+ }
375565
375571
  if (envFlag) {
375566
375572
  const match = environments.find((e) => e.name === envFlag);
375567
375573
  if (!match) {
@@ -375624,6 +375630,45 @@ function DeployUI({ envFlag, config }) {
375624
375630
  cancelled = true;
375625
375631
  };
375626
375632
  }, [state.phase, state.projectId]);
375633
+ useEffect6(() => {
375634
+ if (state.phase !== "creating-preview" || !state.projectId) return;
375635
+ let cancelled = false;
375636
+ async function createPreview() {
375637
+ try {
375638
+ const token = await getValidAccessToken();
375639
+ const client2 = new SpecificClient({ accessToken: token });
375640
+ const projectDir = process.cwd();
375641
+ const previousPreviewId = readPreviewEnvironmentId(projectDir);
375642
+ if (previousPreviewId) {
375643
+ setState((s) => ({ ...s, previewStatus: "Tearing down previous preview environment" }));
375644
+ try {
375645
+ await client2.deletePreviewEnvironment(previousPreviewId);
375646
+ } catch {
375647
+ }
375648
+ }
375649
+ if (cancelled) return;
375650
+ setState((s) => ({ ...s, previewStatus: "Creating preview environment" }));
375651
+ const previewEnv = await client2.createPreviewEnvironment(state.projectId);
375652
+ writePreviewEnvironmentId(previewEnv.id, projectDir);
375653
+ if (cancelled) return;
375654
+ setState((s) => ({
375655
+ ...s,
375656
+ phase: "creating-tarball",
375657
+ environmentName: previewEnv.name
375658
+ }));
375659
+ } catch (err) {
375660
+ if (cancelled) return;
375661
+ setState({
375662
+ phase: "error",
375663
+ error: err instanceof Error ? err.message : String(err)
375664
+ });
375665
+ }
375666
+ }
375667
+ createPreview();
375668
+ return () => {
375669
+ cancelled = true;
375670
+ };
375671
+ }, [state.phase, state.projectId]);
375627
375672
  const handleEnvironmentSelect = useCallback3(
375628
375673
  (env2) => {
375629
375674
  writeEnvironmentId(env2.id);
@@ -376175,7 +376220,14 @@ function DeployUI({ envFlag, config }) {
376175
376220
  }
376176
376221
  return "Preparing";
376177
376222
  };
376178
- return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", gap: 1 }, /* @__PURE__ */ React7.createElement(Text7, null, /* @__PURE__ */ React7.createElement(Text7, { bold: true, color: "cyan" }, "Deploying to ", environment), deployment && /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, " (", deployment.id, ")")), /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column" }, /* @__PURE__ */ React7.createElement(
376223
+ return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", gap: 1 }, /* @__PURE__ */ React7.createElement(Text7, null, /* @__PURE__ */ React7.createElement(Text7, { bold: true, color: "cyan" }, preview ? `Deploying preview${environment !== "prod" ? ` (${environment})` : ""}` : `Deploying to ${environment}`), deployment && /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, " (", deployment.id, ")")), /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column" }, preview && /* @__PURE__ */ React7.createElement(
376224
+ PhaseIndicator,
376225
+ {
376226
+ phase: "creating-preview",
376227
+ currentPhase: displayPhase,
376228
+ label: state.previewStatus || "Creating preview environment"
376229
+ }
376230
+ ), /* @__PURE__ */ React7.createElement(
376179
376231
  PhaseIndicator,
376180
376232
  {
376181
376233
  phase: "creating-tarball",
@@ -376492,7 +376544,7 @@ async function deployCommand(options2) {
376492
376544
  console.error(formatConfigError(err, hcl, configPath));
376493
376545
  process.exit(1);
376494
376546
  }
376495
- const hasNonInteractiveFlags = options2.project || options2.secret?.length || options2.config?.length || options2.preview;
376547
+ const hasNonInteractiveFlags = options2.project || options2.secret?.length || options2.config?.length;
376496
376548
  if (!isInteractive() || hasNonInteractiveFlags) {
376497
376549
  await runDeployPipeline({
376498
376550
  config,
@@ -376509,6 +376561,7 @@ async function deployCommand(options2) {
376509
376561
  DeployUI,
376510
376562
  {
376511
376563
  envFlag: options2.env,
376564
+ preview: options2.preview,
376512
376565
  config
376513
376566
  }
376514
376567
  )
@@ -377369,7 +377422,7 @@ function compareVersions(a, b) {
377369
377422
  return 0;
377370
377423
  }
377371
377424
  async function checkForUpdate() {
377372
- const currentVersion = "0.1.123";
377425
+ const currentVersion = "0.1.125";
377373
377426
  const response = await fetch(`${BINARIES_BASE_URL}/latest?t=${Date.now()}`);
377374
377427
  if (!response.ok) {
377375
377428
  throw new Error(`Failed to check for updates: HTTP ${response.status}`);
@@ -377639,7 +377692,7 @@ async function projectListCommand() {
377639
377692
  var program = new Command();
377640
377693
  var env = "production";
377641
377694
  var envLabel = env !== "production" ? `[${env.toUpperCase()}] ` : "";
377642
- program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.123").enablePositionalOptions();
377695
+ program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.125").enablePositionalOptions();
377643
377696
  program.command("init").description("Initialize project for use with a coding agent").option("--agent <name...>", "Agents to configure (cursor, claude, codex, other)").addHelpText("after", `
377644
377697
  Examples:
377645
377698
  $ specific init
@@ -22,9 +22,7 @@ A full development environment can be started with `specific dev`. To deploy any
22
22
  - [Storage](/storage): define S3-compatible object/blob storage for services to store files in.
23
23
  - [Redis](/redis): define non-durable Redis-compatible databases for caching and more.
24
24
  - [Volumes](/volumes): define persistent storage volumes for services to store files in.
25
- <!-- beta:temporal -->
26
25
  - [Temporal](/temporal): managed durable workflow engine for background tasks, AI agents, cron jobs and more.
27
- <!-- /beta:temporal -->
28
26
  <!-- beta:mail -->
29
27
  - [Mail](/mail): managed email sending via SMTP for transactional emails.
30
28
  <!-- /beta:mail -->
@@ -37,7 +35,7 @@ The following is a list of common frameworks and libraries with guidance on how
37
35
  - [Next.js](/integrations/nextjs): full-stack React framework
38
36
  - [Drizzle ORM](/integrations/drizzle): TypeScript ORM with type safety
39
37
  - [Prisma](/integrations/prisma): TypeScript ORM with auto-generated client
40
- - [Temporal](/integrations/temporal): durable workflow engine for background tasks, AI agents, cron jobs, batch jobs and more
38
+ - [Temporal](/integrations/temporal): using Temporal with Specific for durable workflows, background tasks, AI agents, cron jobs and more
41
39
 
42
40
  ## Adding Specific to existing projects / migrating to Specific
43
41
 
@@ -1,93 +1,3 @@
1
1
  # Temporal
2
2
 
3
- <!-- beta:temporal -->
4
- > **Beta**: Specific now has built-in Temporal support. See [Temporal](/temporal) for the recommended approach using the `temporal` block. The manual setup below still works but is no longer needed.
5
- <!-- /beta:temporal -->
6
-
7
- Temporal is a durable workflow engine. This guide covers running Temporal locally during development and connecting to Temporal Cloud in production.
8
-
9
- Temporal has extensive SDK support across many languages including TypeScript, Python, Go, Java, .NET, and PHP. See the [Temporal documentation](https://docs.temporal.io/) for language-specific guides on implementing workers, workflows, and activities. This document only covers integration with Specific.
10
-
11
- ## Configuration
12
-
13
- Define a dev-only Temporal service that runs locally, along with configs and secrets for production Temporal Cloud.
14
-
15
- ```hcl
16
- build "app" {
17
- base = "node"
18
- }
19
-
20
- # Dev-only service: runs local Temporal server during development
21
- # No top-level command means it's excluded from production deployment
22
- #
23
- service "temporal" {
24
- endpoint "grpc" {}
25
- endpoint "ui" { public = true }
26
-
27
- dev {
28
- command = "temporal server start-dev --port $GRPC_PORT --ui-port $UI_PORT --db-filename /tmp/temporal.db"
29
- env = {
30
- GRPC_PORT = endpoint.grpc.port
31
- UI_PORT = endpoint.ui.port
32
- }
33
- }
34
- }
35
-
36
- # Temporal Cloud address (e.g., your-namespace.tmprl.cloud:7233)
37
- config "temporal_address" {}
38
-
39
- # Namespace - uses "default" in dev, must be set for production
40
- config "temporal_namespace" {
41
- dev {
42
- default = "default"
43
- }
44
- }
45
-
46
- # API key for Temporal Cloud - not required in dev
47
- secret "temporal_api_key" {
48
- dev {
49
- required = false
50
- }
51
- }
52
-
53
- service "app" {
54
- build = build.app
55
- command = "node index.js"
56
- expose {}
57
-
58
- env = {
59
- PORT = port
60
- TEMPORAL_ADDRESS = config.temporal_address
61
- TEMPORAL_NAMESPACE = config.temporal_namespace
62
- TEMPORAL_API_KEY = secret.temporal_api_key
63
- }
64
-
65
- dev {
66
- command = "node --watch index.js"
67
- env = {
68
- # Override to use local Temporal service instead
69
- TEMPORAL_ADDRESS = ""
70
- TEMPORAL_HOST = service.temporal.endpoint.grpc.host
71
- TEMPORAL_PORT = service.temporal.endpoint.grpc.port
72
- }
73
- }
74
- }
75
- ```
76
-
77
- ## Development
78
-
79
- Running `specific dev` automatically starts a local Temporal server. The user must install the Temporal CLI for this: https://temporal.io/setup/install-temporal-cli. The Temporal Web UI is available at the public endpoint URL shown in the output.
80
-
81
- Your app connects to the local Temporal server using the service endpoint environment variables (`TEMPORAL_HOST` and `TEMPORAL_PORT`).
82
-
83
- ## Production
84
-
85
- In production, the dev-only `temporal` service is excluded from deployment. Your app connects to Temporal Cloud using:
86
-
87
- 1. `temporal_address` - Your Temporal Cloud address (e.g., `your-namespace.tmprl.cloud:7233`)
88
- 2. `temporal_namespace` - Your Temporal Cloud namespace
89
- 3. `temporal_api_key` - API key for authentication
90
-
91
- Set these with `specific secrets set` before deploying.
92
-
93
- ## SDK support
3
+ Specific has built-in Temporal support via the `temporal` block. See [Temporal](/temporal) for the full guide on configuration, development, and production deployment.
@@ -42,6 +42,7 @@ The following PostgreSQL extensions are available in both development and produc
42
42
 
43
43
  - **pgvector** (`vector`) - Vector similarity search. Enable with `CREATE EXTENSION vector;` in a migration. See https://github.com/pgvector/pgvector for full documentation.
44
44
  - **pg_search** (`pg_search`) - Full-text search with BM25 ranking, powered by ParadeDB. Enable with `CREATE EXTENSION pg_search;` in a migration. See https://docs.paradedb.com/documentation/getting-started/quickstart for full documentation.
45
+ - **PostGIS** (`postgis`) - Geospatial queries and indexing over geometry and geography types. Enable with `CREATE EXTENSION postgis;` in a migration. See https://postgis.net/documentation/ for full documentation.
45
46
 
46
47
  ## Querying the database
47
48
 
@@ -1,4 +1,3 @@
1
- <!-- beta:temporal -->
2
1
  # Temporal
3
2
 
4
3
  Define managed Temporal workflow engines for durable workflows, background tasks, AI agents, cron jobs, batch jobs and more.
@@ -66,4 +65,3 @@ Running `specific deploy` automatically provisions a managed [Temporal Cloud](ht
66
65
  4. Credentials are securely injected into your services
67
66
 
68
67
  The reference attributes (`temporal.<name>.url`, `.namespace`, `.api_key`) resolve to the Temporal Cloud values in production, so no environment-specific overrides are needed.
69
- <!-- /beta:temporal -->
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@specific.dev/cli",
3
- "version": "0.1.123",
3
+ "version": "0.1.125",
4
4
  "description": "CLI for Specific infrastructure-as-code",
5
5
  "type": "module",
6
6
  "main": "dist/cli.js",