@deslop/stash 0.1.1089 → 0.1.1091

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/README.md CHANGED
@@ -1,7 +1,10 @@
1
1
  # @deslop/stash
2
2
 
3
- Saves a link or text to the owner's stash server over the tailnet and prints the read, tagged note as Markdown.
3
+ Saves a link or text to the owner's stash server and prints the read, tagged note as Markdown.
4
4
 
5
5
  ```bash
6
+ vpx @deslop/stash@latest login '<api key>'
6
7
  vpx @deslop/stash@latest save '<link or text>' [--server <url>]
7
8
  ```
9
+
10
+ `login` keeps an API key created at https://auth.mp281x.xyz in `~/.config/stash/api-key`.
package/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env -S node --max-old-space-size=16384 --heapsnapshot-near-heap-limit=3 --report-on-fatalerror
2
- import { $o as makeSpanScoped, $s as withFiber, $t as String$6, Ad as exists, Ao as flatMap$1, As as serviceOption, Bd as isNone, C as runMain, Cd as getOrUndefinedUnsafe, Co as delay, Ct as HttpClientErrorSchema, D as QuitError, Dc as replace, Do as fail$1, E as layer, Es as runForkWith, Eu as getSomes, F as String$7, Ff as identity, Fn as tag, Fo as forever, Fs as sync$1, Ft as Defect, G as RpcSerialization, Gd as match$1, Go as interruptible, H as Stdio, Hi as runHead, Ho as ignore, Id as fromUndefinedOr, If as pipe, Il as die, Kd as none, Ko as isEffect, Ks as uninterruptibleMask, L as option, Lc as round, Ld as getOrElse, Lf as pipeArguments, Ll as fail, Ln as toCodecStringTree, Lo as forkIn, Ls as tapCause, Lt as Error$1, Lu as map$4, Ms as succeed$1, Nf as dual, Nn as optional$2, No as fnUntraced, Nu as isReadonlyArrayNonEmpty, O as Terminal, Pn as optionalKey, Po as forEach, Ps as suspend, Pu as join, Q as constPing, Qc as interruptors, Qi as unwrap, Ql as sync, Qs as whileLoop, Rc as Clock, Rl as failCause$1, Ro as forkScoped, Ru as match, Sa as makeUnsafe, Sc as isNonEmpty, Sf as isNotUndefined, Sn as is, Ss as result, Su as findLast, T as errorReported, Ta as interrupt$2, Td as make$3, To as ensuring, Uo as ignoreCause, Ut as Literal, Uu as some$1, Vd as isSome, Vl as isFailure, Vo as gen, Vs as timeoutOrElse, Vu as reduce, W as withRunClient, Wd as map$3, Wl as ConsoleRef, Wo as interrupt$1, Xc as hasInterrupts, Xs as void_, Y as RequestId, Yd as some, Yo as logError, Ys as useSpan, Zo as logInfo, _a as shutdownUnsafe, _d as Reference, _n as encodeEffect, _s as provideContext, _t as layerWebSocket, ad as isSuccess, ar as empty, at as isStreamSchema, b as LogToStderr, bd as empty$1, bl as addFinalizerExit, bs as raceFirst, bu as findFirst, ca as bounded, cs as onError, ct as Collector, da as failCause, dc as min, do as callback, ds as onInterrupt, dt as Socket, ed as fail$2, es as map$2, fl as provide$2, fo as catchCause, ft as SocketError, gs as provide$1, h as NotesError, hd as toMillis, hn as decodeUnknownEffect, ho as catchFilter, hr as value, ht as SocketReadError, hu as empty$2, io as andThen, is as matchCauseEffect, it as getStreamSchemas, j as Crypto, jd as filter, jf as constVoid, jt as BooleanLiterals, k as isQuitError, kl as MinimumLogLevel, ks as scoped, kt as ArraySchema, lr as merge, lt as makeCollectorUnsafe, lu as taggedEnum, ma as offerAll, mf as format, mr as make$2, nc as withParentSpan, nf as Prototype, nn as TaggedError, ns as mapError, of as withFiber$1, ol as effect, oo as annotateLogs, or as fromInput, ot as spanAttributes, pc as spaced, pi as filter$1, pn as decodeSync, po as catchCauseIf, ps as orDie, pt as SocketErrorReason, q as layerJson, qc as findError, qt as NonEmptyArray, rl as squash, rn as TrueLiterals, rs as match$2, sc as exponential, sd as succeed$2, sf as assignProperty, st as spanName, t as RpcContracts, tt as exitSchema, ua as end, un as Union, uo as cached, va as take, vd as Service, vf as hasProperty, vl as Scope, vo as catchTag, vs as provideService, vt as layerWebSocketConstructorGlobal, vu as filter$2, w as errorExitCode, wa as getCurrent, wd as getUnsafe, ws as retryOrElse, xd as get, xi as fromQueue, xo as context, xu as findFirstIndex, yd as add, yl as addFinalizer, yo as catchTags, zd as getOrUndefined, zl as interrupt, zs as timeout, zt as FalseLiterals } from "./contracts-CdQiWFv_.mjs";
2
+ import { $d as make$3, $o as flatMap$1, $s as serviceOption, $t as FalseLiterals, Ac as exponential, Af as Prototype, Ar as make$2, B as Terminal, Bs as provideContext, Bu as empty$2, C as AuthError, Cf as some, Ci as FileSystem, Cl as interruptors, Cs as map$2, Ct as makeCollectorUnsafe, Cu as sync, Dn as decodeSync, Do as andThen, Ds as matchCauseEffect, Dt as SocketErrorReason, Es as match$2, Et as SocketError, F as runMain, Fa as offerAll, Ff as assignProperty, Fl as merge$1, Fo as catchCause, Ga as makeUnsafe, Gc as isNonEmpty, Gd as Reference, Gl as addFinalizerExit, Gs as result, Gt as BooleanLiterals, Gu as findFirst, Hf as format, Hi as fromQueue, Ho as catchTags, I as errorExitCode, Ic as spaced, In as is, Io as catchCauseIf, Is as orDie, J as String$7, Ja as interrupt$2, Jd as empty$1, Jn as optionalKey, Jo as ensuring, Kd as Service, Kf as hasProperty, Ko as delay, Ku as findFirstIndex, L as errorReported, Ll as provide$2, Lt as HttpClientErrorSchema, M as LogToStderr, Ma as failCause, Mt as layerWebSocketConstructorGlobal, Nd as succeed$2, No as cached, Ol as squash, Pc as min, Pf as withFiber$1, Pi as filter$1, Po as callback, Ps as onInterrupt, Pu as taggedEnum, Qd as getUnsafe, Qs as scoped, R as layer, Ra as shutdownUnsafe, Ro as catchFilter, S as RpcAuth, Sc as withFiber, Ss as makeSpanScoped, St as Collector, Tc as withParentSpan, Td as fail$2, Tr as merge, Ts as mapError, Tt as Socket, U as Crypto, Ud as toMillis, Ul as Scope, Us as raceFirst, Ut as ArraySchema, Uu as filter$2, V as isQuitError, Vo as catchTag, Vs as provideService, Wl as addFinalizer, Wo as context, Xc as replace, Xf as isNotUndefined, Xo as fail$1, Yd as get, Yn as tag, Ys as runForkWith, Yt as Defect, Z as option, Zd as getOrUndefinedUnsafe, Zn as toCodecStringTree, Zt as Error$1, Zu as getSomes, _n as TrueLiterals, ad as join, af as filter, ap as constVoid, at as RpcSerialization, b as AUTH_URL, bf as none, br as empty, bs as logInfo, bt as spanAttributes, cc as timeout, cd as map$4, cu as fail, df as getOrElse, dp as pipeArguments, ds as ignore, eu as MinimumLogLevel, fd as reduce, fs as ignoreCause, ft as constPing, fu as isFailure, gn as TaggedError, h as NotesError, hc as uninterruptibleMask, hf as isSome, hs as isEffect, ht as exitSchema, hu as ConsoleRef, ic as sync$1, id as isReadonlyArrayNonEmpty, if as exists, is as forever, it as withRunClient, ja as end, jd as isSuccess, jl as effect, jn as encodeEffect, jr as value, js as onError, jt as layerWebSocket, ka as bounded, kn as decodeUnknownEffect, ko as annotateLogs, kt as SocketReadError, la as runHead, ld as match, lp as identity, lt as RequestId, lu as failCause$1, md as some$1, mf as isNone, ms as interruptible, ns as fnUntraced, nt as Stdio, oc as tapCause, ol as round, os as forkIn, pf as getOrUndefined, pn as String$6, ps as interrupt$1, qa as getCurrent, qd as add, qn as optional$2, qs as retryOrElse, qu as findLast, rc as suspend, rn as Literal, rs as forEach, sl as Clock, sn as NonEmptyArray, sp as dual, ss as forkScoped, st as layerJson, su as die, t as RpcContracts, tc as succeed$1, uc as timeoutOrElse, uf as fromUndefinedOr, up as pipe, us as gen, uu as interrupt, vc as useSpan, vf as map$3, vl as findError, vs as logError, vt as getStreamSchemas, wn as Union, xc as whileLoop, xl as hasInterrupts, xr as fromInput, xt as spanName, ya as unwrap, yc as void_, yf as match$1, yt as isStreamSchema, z as QuitError, za as take, zs as provide$1 } from "./contracts-C1Rqhg6U.mjs";
3
3
  //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/workers/WorkerError.js
4
4
  /**
5
5
  * Worker error reason for failures while spawning or setting up a worker.
@@ -1524,6 +1524,51 @@ const Choice = (choices) => {
1524
1524
  return Object.assign(primitive, { choiceKeys: choices.map(([key]) => key) });
1525
1525
  };
1526
1526
  /**
1527
+ * Creates a primitive that wraps string input in `Redacted`.
1528
+ *
1529
+ * **Details**
1530
+ *
1531
+ * The wrapped value is hidden when formatted or inspected, while the original
1532
+ * string remains available through the `Redacted` API when explicitly needed.
1533
+ *
1534
+ * **Example** (Parsing redacted values)
1535
+ *
1536
+ * ```ts import.meta.vitest
1537
+ * import { Effect, FileSystem, Layer, Path, Redacted, Stdio, Terminal } from "effect"
1538
+ * import { Primitive } from "effect/cli"
1539
+ * import { ChildProcessSpawner } from "effect/process"
1540
+ *
1541
+ * const CliTestLayer = Layer.mergeAll(
1542
+ * FileSystem.layerNoop({}),
1543
+ * Path.layer,
1544
+ * Stdio.layerTest({}),
1545
+ * Layer.succeed(Terminal.Terminal, Terminal.make({
1546
+ * columns: Effect.succeed(80),
1547
+ * rows: Effect.succeed(24),
1548
+ * readInput: Effect.die("unused"),
1549
+ * readLine: Effect.die("unused"),
1550
+ * display: () => Effect.void
1551
+ * })),
1552
+ * Layer.succeed(
1553
+ * ChildProcessSpawner.ChildProcessSpawner,
1554
+ * ChildProcessSpawner.make(() => Effect.die("unused"))
1555
+ * )
1556
+ * )
1557
+ *
1558
+ * const parseRedacted = Effect.gen(function*() {
1559
+ * const result = yield* Primitive.Redacted.parse("secret-password")
1560
+ * return [Redacted.value(result), String(result)] as const
1561
+ * })
1562
+ *
1563
+ * await Effect.runPromise(parseRedacted.pipe(Effect.provide(CliTestLayer))) // => ["secret-password", "<redacted>"]
1564
+ * ```
1565
+ *
1566
+ * @stability unstable
1567
+ * @category constructors
1568
+ * @since 4.0.0
1569
+ */
1570
+ const Redacted$2 = /*#__PURE__*/ makePrimitive("Redacted", (value) => succeed$1(make$2(value)));
1571
+ /**
1527
1572
  * Gets a human-readable type name for a primitive.
1528
1573
  *
1529
1574
  * **When to use**
@@ -3406,6 +3451,34 @@ const ChoiceWithValue$1 = (kind, name, choices) => makeSingle({
3406
3451
  primitiveType: Choice(choices),
3407
3452
  kind
3408
3453
  });
3454
+ /**
3455
+ * Creates a redacted parameter for sensitive data like passwords.
3456
+ * The value is masked in help output and logging.
3457
+ *
3458
+ * **Example** (Creating redacted parameters)
3459
+ *
3460
+ * ```ts import.meta.vitest
3461
+ * import { Param } from "effect/cli"
3462
+ *
3463
+ * // Create a password parameter
3464
+ * const password = Param.Redacted(Param.flagKind, "password")
3465
+ *
3466
+ * // Create an API key argument
3467
+ * const apiKey = Param.Redacted(Param.argumentKind, "api-key")
3468
+ *
3469
+ * // Usage: --password (value will be hidden in help/logs)
3470
+ * const kinds = [password.kind, apiKey.kind] // => ["flag", "argument"]
3471
+ * ```
3472
+ *
3473
+ * @stability unstable
3474
+ * @category constructors
3475
+ * @since 4.0.0
3476
+ */
3477
+ const Redacted$1 = (kind, name) => makeSingle({
3478
+ name,
3479
+ primitiveType: Redacted$2,
3480
+ kind
3481
+ });
3409
3482
  const FLAG_DASH_REGEXP = /^-+/;
3410
3483
  /**
3411
3484
  * Adds an alias to an option.
@@ -3943,6 +4016,23 @@ const getParamMetadata = (param) => {
3943
4016
  */
3944
4017
  const String$2 = (name) => String$3(argumentKind, name);
3945
4018
  /**
4019
+ * Creates a positional redacted argument that obscures its value.
4020
+ *
4021
+ * **Example** (Creating a redacted argument)
4022
+ *
4023
+ * ```ts import.meta.vitest
4024
+ * import { Argument } from "effect/cli"
4025
+ *
4026
+ * const secret = Argument.Redacted("secret")
4027
+ * secret.kind // => "argument"
4028
+ * ```
4029
+ *
4030
+ * @stability unstable
4031
+ * @category constructors
4032
+ * @since 4.0.0
4033
+ */
4034
+ const Redacted = (name) => Redacted$1(argumentKind, name);
4035
+ /**
3946
4036
  * Adds a description to a positional argument.
3947
4037
  *
3948
4038
  * **Example** (Adding an argument description)
@@ -7600,15 +7690,27 @@ const runWith = (command, config) => {
7600
7690
  };
7601
7691
  //#endregion
7602
7692
  //#region package.json
7603
- var version = "0.1.1089";
7693
+ var version = "0.1.1091";
7604
7694
  //#endregion
7605
7695
  //#region src/main.cli.ts
7696
+ const server = pipe(String$1("server"), withDescription$1("Stash server; defaults to STASH_SERVER, then https://stash.mp281x.xyz"), withFallbackConfig(String$7("STASH_SERVER")), withDefault("https://stash.mp281x.xyz"));
7697
+ const keyFolder = map$2(String$7("HOME"), (home) => `${home}/.config/stash`);
7606
7698
  function section(title, text) {
7607
7699
  return pipe(fromUndefinedOr(text), filter(isNonEmpty), map$3((found) => `## ${title}\n\n${found}`));
7608
7700
  }
7701
+ const login = pipe(make("login", { key: pipe(Redacted("api-key"), withDescription$2(`An API key created at ${AUTH_URL}`)) }, fnUntraced(function* (input) {
7702
+ const fs = yield* FileSystem;
7703
+ const folder = yield* keyFolder;
7704
+ yield* fs.makeDirectory(folder, { recursive: true });
7705
+ yield* fs.writeFileString(`${folder}/api-key`, value(input.key), { mode: 384 });
7706
+ yield* logInfo(`Signed in; the API key is in ${folder}/api-key`);
7707
+ })), withDescription(`Keep an API key created at ${AUTH_URL} in ~/.config/stash/api-key for save.`), withExamples([{
7708
+ command: "vpx @deslop/stash@latest login '<api key>'",
7709
+ description: `Sign in with a key from ${AUTH_URL}.`
7710
+ }]));
7609
7711
  const save = pipe(make("save", {
7610
7712
  entry: pipe(String$2("text"), withDescription$2("A link, or the text of a note")),
7611
- server: pipe(String$1("server"), withDescription$1("Stash server; defaults to STASH_SERVER, then the tailnet address on dev"), withFallbackConfig(String$7("STASH_SERVER")), withDefault("https://dev.tailnet-8c4c.ts.net:8443"))
7713
+ server
7612
7714
  }, fnUntraced(function* (input) {
7613
7715
  const note = yield* pipe(gen(function* () {
7614
7716
  const client = yield* make$1(RpcContracts);
@@ -7639,10 +7741,15 @@ const save = pipe(make("save", {
7639
7741
  section("Transcript", note.transcript),
7640
7742
  section("Issue", note.issue)
7641
7743
  ], getSomes, filter$2(isNonEmpty), join("\n\n")));
7642
- })), provide((input) => pipe(layerProtocolSocket({ pingTimeout: "15 seconds" }), provide$2(layerWebSocket(pipe(new URL("/api/rpc", input.server).href, replace(/^http/u, "ws")))), provide$2(layerWebSocketConstructorGlobal), provide$2(layerJson))), withDescription("Save a link or a note to stash and print it as Markdown: title, summary, tags, notes, source text and the transcript with [mm:ss] timestamps. The server reads the link, transcribes its video with published captions or Whisper, and tags it; the CLI waits until it finishes. Needs the tailnet."), withExamples([{
7744
+ })), provide((input) => merge$1(pipe(layerProtocolSocket({ pingTimeout: "15 seconds" }), provide$2(layerWebSocket(pipe(new URL("/api/rpc", input.server).href, replace(/^http/u, "ws")))), provide$2(layerWebSocketConstructorGlobal), provide$2(layerJson)), RpcAuth.layerClient(pipe(gen(function* () {
7745
+ return yield* (yield* FileSystem).readFileString(`${yield* keyFolder}/api-key`);
7746
+ }), mapError((cause) => AuthError.make({
7747
+ cause,
7748
+ message: `Sign in first: create an API key at ${AUTH_URL}, then run stash login '<api key>'`
7749
+ })))))), withDescription("Save a link or a note to stash and print it as Markdown: title, summary, tags, notes, source text and the transcript with [mm:ss] timestamps. The server reads the link, transcribes its video with published captions or Whisper, and tags it; the CLI waits until it finishes. Needs `stash login` first."), withExamples([{
7643
7750
  command: "vpx @deslop/stash@latest save https://x.com/poteto/status/2102050467505430555",
7644
7751
  description: "Save the talk attached to an X post and print its note and transcript."
7645
7752
  }]));
7646
- runMain(pipe(make("stash"), withDescription("Save links and notes to stash; the server and iOS app share this package."), withSubcommands([save]), run({ version }), provideService(LogToStderr, true), provide$1(layer)));
7753
+ runMain(pipe(make("stash"), withDescription("Save links and notes to stash; the server and iOS app share this package."), withSubcommands([login, save]), run({ version }), provideService(LogToStderr, true), provide$1(layer)));
7647
7754
  //#endregion
7648
7755
  export {};